Reputation: 1589
I will try to state this question as short and to the point as possible.
I expected this computation to complete after inputting three characters to the command line. However, it does not. I am curious as to why this is.
return . take 3 =<< sequence (repeat getChar)
Edit:
I should add that I am trying to separate selection from generation and therefore wish to produce an infinite stream of characters that I select from.
Upvotes: 2
Views: 269
Reputation: 24802
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.
Upvotes: 7
Reputation: 47052
=<<
complete before effects to the left of =<<
begin.
=<<
would run forever then the entire action will run forever.sequence
takes a list of actions and gives back an action that performs all those actions.
sequence
an infinite list of actions, it will run forever.repeat
takes a value, and gives an infinite list of that value, repeated.Do you see now why you get the behaviour you experience?
This would work, because there is no infinite list:
sequence (take 3 $ repeat getChar)
But presumably your real selection function is more complicated than "take the first three". What is it?
Upvotes: 6