Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

list monad transformer

I need to use a list monad transformer. I've read that there are potential problems with ListT IO from Control.Monad.List, since IO isn't commutative, so I'm looking at ListT done right. But I'm getting some unexpected behavior.

Consider this simple test:

test = runListT $ do
  x <- liftList [1..3]
  liftIO $ print x
  y <- liftList [6..8]
  liftIO $ print (x,y)

Using Control.Monad.List:

Main> test
1
(1,6)
(1,7)
(1,8)
2
(2,6)
(2,7)
(2,8)
3
(3,6)
(3,7)
(3,8)
[(),(),(),(),(),(),(),(),()]

Using "ListT done right":

Main> test
1
(1,6)

Is this a problem with "ListT done right", or am I just using it wrong? Is there a preferred alternative?

Thanks!

like image 259
Chad Scherrer Avatar asked Mar 15 '12 18:03

Chad Scherrer


People also ask

Is every Monad Transformer a Monad?

All monad transformers are instances of MonadTrans , and so lift is available for them all. There is a variant of lift specific to IO operations, called liftIO , which is the single method of the MonadIO class in Control. Monad. IO.

What is liftIO?

liftIO allows us to lift an IO action into a transformer stack that is built on top of IO and it works no matter how deeply nested the stack is.

What is a Haskell Monad?

In Haskell a monad is represented as a type constructor (call it m ), a function that builds values of that type ( a -> m a ), and a function that combines values of that type with computations that produce values of that type to produce a new computation for values of that type ( m a -> (a -> m b) -> m b ).


1 Answers

This might be intensional on the part of the author, since they say

it lets each element of the list have its own side effects, which only get `excecuted' if this element of the list is really inspected.

I'm not sure, though. Anyway, you can use this function to sequence the whole list:

runAll_ :: (Monad m) => ListT m a -> m ()
runAll_ (ListT m) = runAll_' m where
    runAll_' m = do
        mm <- m
        case mm of
             MNil          -> return ()
             _ `MCons` mxs -> runAll_' mxs

And an analogous runAll that returns a list should be easy to construct.

main = runAll_ $ do
    x <- liftList [1..3]
    liftIO $ print x
    y <- liftList [6..8]
    liftIO $ print (x,y)

1
(1,6)
(1,7)
(1,8)
2
(2,6)
(2,7)
(2,8)
3
(3,6)
(3,7)
(3,8)
like image 187
Owen Avatar answered Oct 06 '22 21:10

Owen