如何使用ListT单子变换器

4

我是一个Haskell中的Monad Transformers新手,尤其是在ListT Monad Transformer方面我很困惑。

我希望在进行一些IO操作的同时计算一个列表。

这里有一个愚蠢的例子,它无法编译。我想打印列表中每个成员x加1的结果。

import Control.Monad
import Control.Monad.Trans.List
import Control.Monad.Trans.Class 
import System.IO.Unsafe

scrap :: ListT IO Int
scrap = do lift $ print "Hello"
           lift $ print 6
           x <- [6,7,8]
           lift $ print (x+1) -- code crashes here
           return 4

这段代码不能被编译,会出现以下错误:

[1 of 1] Compiling Main             ( problem.hs, interpreted )

problem.hs:41:17:
    Couldn't match expected typeListT IO Integer
                with actual type ‘[Integer]’
    In a stmt of a 'do' block: x <- [6, 7, 8]
    In the expression:
      do { lift $ print "Hello";
           lift $ print 6;
           x <- [6, 7, ....];
           lift $ print (x + 1);
           .... }
    In an equation for ‘scrap’:
        scrap
          = do { lift $ print "Hello";
                 lift $ print 6;
                 x <- [6, ....];
                 .... }
Failed, modules loaded: none.

我想要代码打印出7,8,9,我应该怎么做?

3
警告一下,文档中写道:“ ListT 修饰子将回溯功能添加到给定的单子中,该单子必须是可交换的。” IO 不是可交换的(这意味着你执行效果的顺序并不重要,在 IO 中则很不正确)。这就意味着你不能得到单子定律 - 例如,如果你写 do { do { foo; bar }; baz } 它的行为可能与你写 do { foo; do { bar; baz } } 不同。而且谁知道它们的差异应该是什么? - 基本上就没有意义了。 - luqui
2
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - luqui
1
你的问题在于[6,7,8]的类型是[Int],但编译器期望的是ListT IO Int。因此,你需要进行转换[Int]-> ListT IO Int。例如,ListT . return $ [6,7,8] - freestyle
2
你应该使用“ListT done right”库之一,原因如luqui所述。 list-transformer有一些不错的教程材料。(使用该库,freestyle更正的有问题的行将被写成select [6,7,8])Hackage上有几种不同的实现,例如list-t - Michael
1个回答

3
以下是完整的程序以回答这个问题。 首先,从功能的角度来看,我认为您需要的比 ListT 或只是 IO Int 更简单。 其次,也许您想学习 ListT,因此我还提供了 ListT 版本。 该程序还可以作为理解 list-t 库中的 toListtraverse_ 函数的示例。 另一个流式库中精彩地解释了它们之间的差异:https://github.com/snoyberg/conduit#interleaved-effects 编译前,请在 package.yaml 文件中添加 mtllist-t 作为依赖项(假设您正在使用 stack)。
import qualified ListT as L
import Control.Monad.Trans (lift)

main :: IO ()
main =  putStrLn "#### Just IO version: maybe you are actually looking for this."
     >> scrapJustIO >>= print
     >> putStrLn "#### ListT version serializing everything into a list before output."
     >> L.toList scrapListT >>= print
     >> putStrLn "#### ListT version as stream (what list-t is actually for)"
     >> L.traverse_ print scrapListT

scrapJustIO :: IO Int
scrapJustIO = do
    putStrLn "Hello"
    print 6
    mapM_ (print . (+1)) [6,7,8]
    return 4

scrapListT :: L.ListT IO Int
scrapListT = do
    lift $ putStrLn "Hello"
    lift $ print 6
    x <- L.fromFoldable [6,7,8]
    lift $ print (x+1)
    return 4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接