Lazy IO in haskell: How to return a lazy list that is generated by some locked IO?
getText = do
c <- getChar
s <- getText
return (c : s)
main = do
s <- getText
putStr s
What I expect to see is that the input string echoes every time after I hit 'Enter'. But nothing echoes ... (I know this is an infinite loop) It looks like it won't " return
" until all the "IOs" on it are done ....
However, the following code:
main = do
s <- getContents
putStr s
Displays the string immediately after typing.
Given a function getChar
, can I write getText
that behaves like getContents
?
source to share
This can be accomplished using a function unsafeInterleaveIO
from
System.IO.Unsafe
. Then your function getText
will become
getText = do
c <- getChar
s <- unsafeInterleaveIO $ getText
return (c : s)
Abstracting a little, we can get a function to generalize this behavior
lazyDoIO :: IO a -> IO [a]
lazyDoIO act = unsafeInterleaveIO $ do
now <- act
rest <- lazyDoIO act
return (now : rest)
getText = lazyDoIO getChar
However, most Haskellers would cringe at the same time. If you want to do incremental processing of the IO
generated data stream , it would be much safer to use a library like Pipes
or Conduits
.
source to share
This is a job for ... unsafeInterleaveIO
- a special action that makes lazy IO possible. This allows you to turn the I / O action into a single thunk. This can then be stored in a framework and the action will only be evaluated when its result is required.
getText = unsafeInterleaveIO $ do
c <- getChar
s <- getText
return (c : s)
Now yours getText
returns immediately with only computation suspended for each getChar. If you want the result, it runs.
source to share