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

?

+3


source to share


3 answers


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

.

+7


source


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.

+8


source


You are talking about Input, but you are not checking it in your code.

Try the following:

getText = do
    c <- getChar
    if (c == '\n')
       then return [c]
       else do
              s <- getText
              return (c : s)

main = do
    s <- getText
    putStr s

      

+1


source







All Articles