Kevin Meredith
Kevin Meredith

Reputation: 41909

Understanding ListT IO Example

Given the following from the well-written From Simple IO to Monad Transformers:

import Control.Monad.List

type Lio = ListT IO

test :: Lio ()
test = do
   x <- return [1,2]
   y <- ListT $ return ['a', 'b']
   lift $ putStrLn (show (x, y))

Please explain the final line of output, [(), ()]:

*Main> runListT test
([1,2],'a')
([1,2],'b')
[(),()]

Upvotes: 1

Views: 144

Answers (1)

Zeta
Zeta

Reputation: 105876

TL;DR: If you see something you didn't expect in GHCi, think of the type of the line that yielded that result.


test has the type ListT IO (). If we use runListT on a ListT m a, we end up with a m [a]:

runListT      :: Monad m => ListT  m  a  ->  m  [a]
test          ::            ListT IO ()
runListT test ::                            IO [()]

Since [()] can be shown (and is not ()), GHCi shows you the result. You won't see it if you bind it:

*Main> res <- runListT test
([1,2],'a')
([1,2],'b')
*Main> res
[(),()]

In the end, it's somewhat related to the output of replicateM 10 $ print 1. It collects all the results of print 1, which aren't very interesting. However, it's easy to write runListT_ to get rid of those:

*Main> let runListT_ m = runListT m >> return ()
*Main> runListT_ test
([1,2],'a')
([1,2],'b')

Upvotes: 3

Related Questions