It's better - in so many ways that I will necessarily offer you just a short summary of some of them.
Being able to figure out a meaning of something is crucial in programming. We spend much more time reading the code than writing it and most of the time during reading is spent on resolving the meaning of symbols. To be able to tell what a symbol means, one needs to take into account many things - from OS it's running on to language it's written in to declared variables in the scope. And much more, of course.
Now back to your example: to be able to understand `x::xs` I need to know that `::` is a cons operator. Or more precisely, to understand the meaning of `x` symbol I need to take into account another symbol.
On the other hand of the spectrum is something like this: `first_element_of_list :: rest_of_list`. To understand the meaning of the first symbol in this expression you need to know exactly one symbol - itself. That's one benefit. The second is that someone who doesn't know what consing is, let alone how it's written in OCaml, can still understand this expression. So that's the second benefit.
It's worth remembering that we do not write the code for ourselves nor for the computers. We write the code to be read by other humans (always - don't argue). As with any kind of writing, then, it's helpful to know the audience. If I was writing a tutorial on constructing lists in OCaml (for beginners), I would use the second example above. But if I was writing production code (so for me and my team to read) I would use something shorter, like `head :: tail` for example. And if I was writing a quick and dirty script for my personal use, or if I was contributing to the work of hardcore OCaml hackers I would probably write `x :: xs` - because in case of script I'd be convinced that readability doesn't matter and in second case I would be certain that everyone reading and working with the code I wrote would be already so used to the construction that they would read it without problems.
That's another thing to consider: after using a language for a long enough time we tend to internalize its idioms; when this happens we are able to treat bigger constructs as one symbol. This ability helps in reading the code quickly, but it's worth remembering that not everyone developed it. Also, because longer names do not hinder quick-reading of idioms for those who know them, that's not a counterargument to longer names.
As for loops... Well, I do - sometimes - use `i` as a variable name, but I tend not to. Most often, after a while I come back to the code and replace `i` with `idx`. But to even use `i` as a name in the first place it needs to refer to the nonnegative integer value. In Python you generally iterate over collection directly, so you write `for what_is_it in a_collection:` instead of for example: `for i in 1 to 10: an_element = a_collection[i]`. Anyway, I use single letter variables very sparingly and in the smallest scope possible.
What I want to say, I guess, is that descriptive names are important in good programming and that there is really no argument for using non-descriptive ones.