为什么ListT单子变换器被认为是错误的 - 它破坏了monad法则?

Pet*_*lák 25 monads haskell functional-programming monad-transformers

我见过这个

ListT是一个不满足monad定律的有缺陷的monad变换器的典型例子.

这可以通过一个简单的例子来证明吗?

编辑:我的想法ListT []有点不对,我错过了文档要求内部monad是可交换的.那么,ListT只是在有这个要求的意义上,或者是否存在另一个问题?(Haskell wiki例子都使用ListT IO,IO显然不是可交换的.)

Pet*_*lák 20

一个简单的例子,说明它如何通过相关性法则:

v :: Int -> ListT [] Int
v 0 = ListT [[0, 1]]
v 1 = ListT [[0], [1]]

main = do
    print $ runListT $ ((v >=> v) >=> v) 0
    -- = [[0,1,0,0,1],[0,1,1,0,1],[0,1,0,0],[0,1,0,1],[0,1,1,0],[0,1,1,1]]
    print $ runListT $ (v >=> (v >=> v)) 0
    -- = [[0,1,0,0,1],[0,1,0,0],[0,1,0,1],[0,1,1,0,1],[0,1,1,0],[0,1,1,1]]
Run Code Online (Sandbox Code Playgroud)

更多示例(主要使用IO)和解决方法如何修复ListT可以在ListT完成右侧找到.

  • 嗯......他们被称为"monad变形金刚",而不是"可交换的monad变形金刚".如果我定义的变压器在应用于少数特定的单子组时才能正常工作,那么有人会认为这令人满意吗? (10认同)
  • @CAMcCann是的.令我感到困惑的是,尽管`ListT`的问题是已知的,甚至有一个建议的解决方案([ListT完成正确](http://www.haskell.org/haskellwiki/ListT_done_right))它仍然保持这种形式Haskell的标准库. (3认同)
  • 这些行中的`ListT`版本无法正确捕获`[]`的许多用法,但是 - 具体地说,使用将列表视为多重集而不是序列的情况,即有限列表,其中元素的顺序不是'无所谓.当然这正是问题 - 破坏的`ListT`假定内部monad中的`(>> =)`应用程序的顺序也无关紧要,而"完成正确"的版本在每个都插入包装的monad步入(可能是无限的)流.后者捕获"列表作为控制结构"的想法,因此与iteratee-ish流有关. (3认同)
  • 文件说改造后的单子必须是可交换的; 尝试使用例如`vn = ListT $ map(read :: String - > Int).排列.节目 .(+ n)的` (2认同)
  • @applicative是的,添加这样的类会很有帮助.我们可以简单地使用`Monad m => MonadCommutative m`(和MonadTrans`相同),没有其他方法.然后任何可交换的方法都会被这个类简单地标记出来. (2认同)