I think new programs are supposed to be even more efficient if they use ByteString instead of String for I/O. I am not sure how much of a difference there is.
If the optimizer was good enough, it should be able to optimize most String manipulations anyway, so there would be no difference. Just don't allocate a seperate [Char] object in the heap for each character. Especially it should be possible if you scan the input lazily, since each list element created would immediately be consumed, so no need to allocate memory for it. I am not sure if GHC does that though.