【问题标题】:list monad transformer列出单子转换器
【发布时间】:2012-03-15 18:34:23
【问题描述】:

我需要使用列表单子转换器。我从Control.Monad.List 了解到ListT IO 存在潜在问题,因为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 做得对”的问题,还是我只是用错了?有没有首选的替代方案?

谢谢!

【问题讨论】:

    标签: haskell monads generic-list monad-transformers


    【解决方案1】:

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

    它让列表的每个元素都有自己的副作用,它只会得到 如果确实检查了列表的这个元素,则执行“执行”。

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

    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)
    

    【讨论】:

    • 嗯,好吧,这是有道理的,您的runAll_ 想法非常好!我期待的行为类似于使用命令式语言的 print 语句的嵌套 for 循环。但是如果“ListT done right”是惰性的,为什么它仍然会对列表的头部产生副作用?
    • 假设你总是至少想要第一个元素,所以它将“整个列表”包装在m中,并将cdr包装在m中;车子没有包裹。如果你对“整个列表”进行排序,它只会暴露汽车。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-03
    • 2023-03-07
    • 1970-01-01
    • 2018-02-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多