14

我需要使用列表单子变压器。ListT IO我读过from存在潜在问题Control.Monad.List,因为IO它不是可交换的,所以我正在查看ListT done right。但我得到了一些意想不到的行为。

考虑这个简单的测试:

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

使用 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)
[(),(),(),(),(),(),(),(),()]

使用“ListT 做得对”:

Main> test
1
(1,6)

这是“ListT 做得对”的问题,还是我只是用错了?有首选的替代方案吗?

谢谢!

4

1 回答 1

8

这可能是作者的意图,因为他们说

它让列表的每个元素都有自己的副作用,只有在真正检查了列表的这个元素时才会“执行”。

不过,我不确定。无论如何,您可以使用此函数对整个列表进行排序:

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

并且返回列表的类似物runAll应该很容易构建。

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)
于 2012-03-15T19:28:43.003 回答