为什么`>>`的list monad方法不能定义为`flip const`?

Lui*_*las 3 monads haskell

是否有一些理由为什么Prelude没有像这样定义列表monad?(注意非标准的实现>>.)

instance  Monad []  where
    m >>= k          = concat (map k m)
    m >> k           = k                 -- a.k.a. flip const
    return x         = [x]
    fail s           = []
Run Code Online (Sandbox Code Playgroud)

我试图按照monad法律对此进行检查,但他们没有提及>>.在Monad类的定义是这样的:

m >> k = m >>= \_ -> k
Run Code Online (Sandbox Code Playgroud)

[]实例中将转换为:

concat (map (\_ -> k) m)
Run Code Online (Sandbox Code Playgroud)

这当然不等于flip const- 比如,它们会产生明显不同的结果[1..5] >> return 1.但是我不清楚这个默认定义是否是必须遵守的实例的法则Monad,或者只是满足flip const实现也将满足的其他一些法律的默认实现.

直观地,考虑到列表monad 的意图("非确定性计算"),似乎替代定义>>将同样好,如果不是更好,这要归功于修剪分支,保证等于一个.或者另一种说法是,如果我们处理集合而不是列表,那么两个候选定义将是等价的.但是我在这里错过了一些微妙之处,这使得flip const列表的定义错了吗?

编辑:ehird的答案捕获了上面的一个非常明显的缺陷,即它得到了错误的预期结果[] >> k,应该是[],而不是k.不过,我认为这个问题可以修改为这个定义:

[] >> k = []
_ >> k = k
Run Code Online (Sandbox Code Playgroud)

ehi*_*ird 14

a >> b必须始终相当于a >>= const b; 它只在Monad类中,因此您可以定义更高效(但在语义上等效)的版本.这就是为什么它不是monad定律的一部分:它不是monad定义的一部分,只是类型类(如fail).

不幸的是,我在基础软件包的文档中找不到任何明确说明的基础软件包,但我认为旧版本可能已(>>)Monad类型类之外定义.

对于它的价值,你的定义(>>)打破了monad用于非确定性计算的列表monad.既然[]用来代表失败,[] >> m必须永远[]; 在你耗尽所有可能的分支后,你不能继续!这也意味着这两个方案:

do { m; ... }
do { _ <- m; ... }
Run Code Online (Sandbox Code Playgroud)

可能会有不同的行为,因为前者与(>>)后者有关,后者与后者有关(>>=).(参见Haskell 2010报告.)

  • 基本问题是`[()]`和`[(),()]`不代表同一个东西.列表monad只是模拟非确定性计算的许多monad之一.如果`Set`是Haskell中的monad,那么你*将能够为它定义`(>>)`.但是列表是有序的并允许重复,所以它不会起作用; 即使`(>>)`不仅仅是`(>> =)`的简写并且放弃了参数,它也会以惊人的方式打破语义. (7认同)