[Haskell-cafe] Re: IO in lists

Dan Piponi dpiponi at gmail.com
Mon Jan 22 18:33:59 EST 2007

Magnus Therning asked:

> but how do I go about creating a finite list, e.g. a list that ends as
> soon as 'q' is pressed?

A slightly different approach that doesn't use anything unsafe:

What you want is to return something like an IO [Char] but it needs to
be able to interleave IO. A list of type [Char] is essentially a
solution to the equation
X = Maybe (Char,X)
It's either the empty list (represented by Nothing) or Just a pair of
the head and tail of the list. But this doesn't allow us to
intersperse IO along the computation of the list. In order to to that
we need a solution to
X = IO (Maybe (Char,X))

So define

data X = X { unX :: IO (Maybe (Char,X)) }

We can now write the 'q' terminated list as

test = X $ do
    a <- getChar
    if a=='q'
        then return Nothing
        else return (Just (a,test))

For all intents and purposes, this is what you want. It reads
characters until it reaches a 'q' and then returns IO Nothing.

To make use of this we can write something like this to print out the
contents of the list:

test2 :: X -> IO ()
test2 test = do
    a <- unX test
    case a of
        Nothing -> return ()
        Just (a,b) -> do
            print a
            test2 b

'test2 test' now prints out one of these q-terminated strings. There
is a bit of clutter because of the X and unX. And it's slightly
wordier because we're using Maybe instead of the nice Haskell List
notation. But I think it does exactly what you want. In particular we
have sepration of concerns - the object 'test' is in charge of
generating data and test2 is responsible for reading it, without
unsafe operations. And it seems to print the characters one at a time
as they are entered (with ghc).

More information about the Haskell-Cafe mailing list