Take a look at the type of the two functions:
def reduce[B >: A](op: (B, B) => B): B
def reduceLeft[B >: A](op: (B, A) => B): B
Notice, how the second argument to op in reduceLeft is A (same as the element type), while in reduce it is B (same as the return value).
This is an important difference. The operation in reduce must be associative, meaning that you can split the list into several segments, apply operation to each of them separately, and then apply it again to the results to combine.
This is important when you want to do things in parallel: reduce can be applied in parallel to different parts of the list, and then the results can be combined.
reduceLeft on the other hand, can only work sequentially (left to right, as the name implies), operation does not have to be associative, and can expect its second parameter to always be an element of the sequence (and the first one – result of the operation so far);
Consider
val sum = (1 to 100).reduce(_ + _)
This yields the same result as (1 to 100).reduceLeft(_ + _), except that the former can be parallelized.
On the other hand:
val strings = (1 to 100).reduceLeft[Any](_.toString + ";" + _.toString)
Should not be written as reduce (even though, in this contrived example, it can, and will even work as long as you stick with serial processing), because the result depends on the order in which elements are fed to the operation.