Well, at first I thought I’d call this post “Doing Haskell without a condom” but decided it was probably best not to. :-) I can’t really take full credit for this post, I’ve stolen almost all of it from emails after I posted a question on haskell-cafe. All praise should go to the helpful people there!

What I wanted to do was model a finite stream of external events as a list and then map a function on that list. The processing of an event should happen as soon as an event is encoutered (one could say that the list of events should be lazy). Due to the wording “external events” the solution will have to be in the IO monad. It’s all a bit vague at this point, so let’s take it down to a more concrete level and then at the end make the solution more generic again. Let’s read characters until we read a `q` and print them.

### First attempt, infinite list

``````listChars :: [IO Char]
listChars = repeat getChars``````

Then I can map `printChar` like this:

``mapM_ (\ x -> x >>= printChar) listChars``

The result is almost what I want, each character is printed immediately. The only problem is that there is no end to the stream of characters. This means that the processing never terminates, that’s not a good thing.

### Recursive (non-)solution

Solving the problem with the infinite list is easy if we do it recursively:

``````processChars :: IO ()
processChars = do
c <- getChar
printChar c
if c == 'q'
then return ()
else processChars``````

This is easy to make more generic, but I expressively wanted to map a function on a list. So a recursive solution won’t cut it this time. However, the same pattern can be used to create a list inside the IO monad:

``````listChars :: IO [Char]
listChars = do
c <- getChar
if c == 'q'
then return [c]
else liftM2 (:) (return c) listChars``````

Now mapping `putChar` on the result of this doesn’t quite produce the desired result.

``listChar >>= mapM_ putChar``

It doesn’t print characters as soon as they are entered. That is, it’s not lazy.

Monads have an ordering effect on things. Since `listChar` executes in the IO monad, and the result then is passed to `putChar`, which also executes in the IO monad, we get a strict ordering between the two functions. What we need is to somehow interleave the IO in `listChars` with the IO in `putChar`. Put interleave into Hoogle and you’re pointed to `unsafeInterleaveIO` in `System.IO.Unsafe`. We can put it to use like this:

``````listChars :: IO [Char]
listChars = unsafeInterleaveIO \$ do
c <- getChar
if c == 'q'
then return [c]
else liftM2 (:) (return c) listChars``````

And now we get the required behaviour. Great!

IO inside on the haskell wiki has the following comment on `unsafeInterleaveIO`:

But there is an even stranger operation called ‘unsafeInterleaveIO’ that gets the “official baton”, makes its own pirate copy, and then runs an “illegal” relay-race in parallel with the main one! I can’t talk further about its behavior without causing grief and indignation, so it’s no surprise that this operation is widely used in countries that are hotbeds of software piracy such as Russia and China! ;) Don’t even ask me - I won’t say anything more about this dirty trick I use all the time ;)

So, I suppose it’s worth the effort to think through just how we put it to use here. Basically one can say that `unsafeInterleaveIO` creates a second IO monad, and in order to keep some level of determinism in the program the use of the new one should be kept separate from the use of the main IO monad, i.e. the one that `main` executes in. In this case the main IO monad is used to print characters to `stdout` while the one created by `unsafeInterleaveIO` reads characters from `stdin`. According to my limited understanding of IO in haskell this should mean we are safe, the two IO monads run no risk of ever “crossing”.

### Another solution

Joachim Breitner suggested another, very cute solution based on cutting the infinite list short.

``````listChars =
let
sequence' (x:xs) = do
r  <- x
rs <- unsafeInterleaveIO (sequence' xs)
return (r:rs)
in do
allChars <- sequence' \$ repeat getChar
let getChars = takeWhile (/= 'q') allChars
return getChars``````

### Generalisations

Recursive solution:

``````listIO :: IO [a] -> (a -> Bool) -> IO [a]
listIO getF testF = unsafeInterleaveIO \$ do
c <- getF
if testF c
then return [c]
else liftM2 (:) (return c) listIO

listChars = listIO getChar ('q' ==)``````

Joachim’s solution:

``````listIO :: IO [a] -> (a -> Bool) -> IO [a]
listIO getF testF=
let
sequence' (x:xs) = do
r  <- x
rs <- unsafeInterleaveIO (sequence' xs)
return (r:rs)
in do
allChars <- sequence' \$ repeat getF
let getA = takeWhile testF allChars
return getA

listChars = listIO getChar ('q' \=)``````

### Could `ListT` be used in a solution?

This was one of my first thoughts. I mean what I want is the combination of two monads, List and IO. So, `ListT IO Char` should offer a solution right?

In theory it could! In practice it doesn’t! Apparantly ListT imposes unnecessary strictness. That means that it doesn’t offer a solution in this case.

Alan Falloon

If your event stream is actually the characters of stdin, then `getContents` already hides the details of the `unsafeInterleaveIO` for you. As in:

``getContents >>= mapM_ yourFunc . takeWhile (/= 'q')``

However, understanding the internals makes it possible to generalize this approach to one where the event stream contains richer data (such as GUI events).

Perhaps there is more that can be learned from FRP (functional reactive programming)

Magnus

Alan,

That’s a very good point. I’ve found that quite a few standard functions are “lazy enough”, just like `getContents`.

Thanks for the link to FRP!