这个奇怪的 monad 绑定是如何工作的?

How does this weird monad bind work?

这可能是一个非常菜鸟的问题,但我在 Haskell 中使用绑定运算符时遇到了一种使用它重复字符串的方法。

[1..3] >>= const "Hey"
-- Yields "HeyHeyHey"
[1..3] >>= return "Hey"
-- Also yields the same result

我理解 >>= (\_ -> return "Hey") 如何产生 ["Hey", "Hey", "Hey"] 但我不明白为什么 (\_ -> "Hey") 重复字符串或者为什么 >>= return "Hey" 做同样的事情。

I understand how >>= (\_ -> return "Hey") would yield ["Hey", "Hey", "Hey"]

没错。 return "Hey" 在这种情况下与 ["Hey"] 相同,因为

instance Monad [] where
  return x = [x]

所以

([1..3] >>= \_ -> return "Hey")
  ≡  ([1..3] >>= \_ -> ["Hey"])
  ≡  ["Hey"] ++ ["Hey"] ++ ["Hey"]
  ≡  ["Hey", "Hey", "Hey"]

现在,>>= (\_ -> "Hey") 也可以用 lambda 中的列表结果来编写,因为字符串只是字符列表。

([1..3] >>= \_ -> "Hey")
  ≡  ([1..3] >>= \_ -> ['H','e','y'])
  ≡  ['H','e','y'] ++ ['H','e','y'] ++ ['H','e','y']
  ≡  ['H','e','y','H','e','y','H','e','y']
  ≡  "HeyHeyHey"

至于 >>= return "Hey",那就另当别论了。 return 在这里属于一个完全不同的 monad,即 function functor.

instance Monad (x->) where
  return y = const y

因此很明显 ([1..3] >>= const "Hey")([1..3] >>= return "Hey") 给出了相同的结果:在那个例子中,return 只是 const![=26 的另一个名称=]

这里使用的 return 不是用于列表 monad,而是用于函数 monad,其中这个定义成立:

return x = \_ -> x

所以这与:

[1,2,3] >>= (\_ -> "Hey")

并且由于 (>>=) 与列表的 concatMap 相同,我们有:

concatMap (\_ -> "Hey") [1,2,3]

你能看出为什么会产生 "HeyHeyHey" 吗?