I/O sequences actions deterministically, so what you are really saying is that you want to execute the getChar
action an infinite number of times and after that has finished, you want to take the three first items from the generated list. You can probably see how this will take a long time.
If you want to perform I/O lazily (and non-deterministically), you can do so using the function unsafeInterleaveIO
from the System.IO.Unsafe
package.
One way to implement what you want is, for example, like this:
import System.IO.Unsafe
lazyIOSequence :: [IO a] -> IO [a]
lazyIOSequence [] = return []
lazyIOSequence (x:xs) = do
first <- unsafeInterleaveIO $ x
rest <- unsafeInterleaveIO $ lazyIOSequence xs
return $ first:rest
test = return . take 3 =<< lazyIOSequence (repeat getChar)
However, the now the actual prompting of data from the user gets delayed until you evaluate elements of the list, so it might not behave as you'd like. In fact, lazy I/O streams are in general considered problematic (see e.g. the questions "Haskell lazy I/O and closing files" and "What's so bad about Lazy I/O?").
The currently recommended way to separate production from selection and processing is to use one of the various strict, stream-processing libraries such as enumerator, pipes or conduit.