It's also important to notice that Data.Vector.Unboxed has the same API as the other Data.Vector implementations and provides the same typechecking that the other implementations do. All it requires is that the underlying type have a Unbox instance. In most cases, you change:
import Data.Vector as V
to
import Data.Vector.Unboxed as V
and your code now gets the performance increase. (The reason it's not the default is because it's not most generic. What if you want to have a vector of IO computations? Good luck unboxing that. But if you just want integers, or something, that's much easier.)
The semantics are different with regard to lazyness: a boxed vector can contain thunks (unevaluated values), so individual elements can be evaluated on demand, while an unboxed vector must be evaluated all at the same time (making it difficult to run a transformation in parallel with multiple threads, for example).
No, because compilers are prohibited from changing the meaning of the program. Changing a lazy value to a strict value is only permitted when the compiler can prove that the value will always be evaluated. It can't do that for unboxed arrays because that is a global change, so it has to leave it to the programmer.