>>运算符 - Haskell中的穷人循环?

use*_*020 2 monads haskell list

我不知道Haskell,我只想玩它来学习它.我试图理解io,monads等,并在解释器(GHCi,版本7.10.2,WinGHCI)中写了这个:

Prelude> [1,1] >> "ok"
"okok"
Prelude> [1,1,1] >> "ok"
"okokok"
Prelude> [1..10] >> "ok"
"okokokokokokokokokok"
Prelude> [1] >> "ok" >> [1] >> "ok"
"okok"
Prelude> [1,2] >> "ok" >> [1,2] >> "ok"
"okokokokokokokok"
Prelude> [1..10] >> [1..10]
[1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10]
Run Code Online (Sandbox Code Playgroud)

小心解释一下?为什么列表中的元素数量会影响写入"ok"的次数(或者在最后一种情况下,是否写入数组的次数)?>>运算符不应该这样做,是吗?

lef*_*out 12

首先请注意,这与此无关IO.它与monad有关,但有一个非常具体的:monad列表.

instance Monad [] where
  return x = [x]
  f >>= xs = concat $ map f xs   -- aka `(>>=) = concatMap`.
Run Code Online (Sandbox Code Playgroud)

最好知道列表推导,基本上是语法糖:

[ result x y z | x <- bla, y <- foo x, z <- bar ]
Run Code Online (Sandbox Code Playgroud)

翻译成

bla >>=
   \x -> foo x >>=
            \y -> bar >>=
                     \z -> return (result x y z)
Run Code Online (Sandbox Code Playgroud)

现在,a>>b它只是一个捷径a >>= \_ -> b,即它忽略了LHS monadic动作中包含的值,但是"假装"在RHS中使用它们.所以,[1,1,1] >> "ok"是一样的

[ "ok" | _ <- [1,1,1] ]
Run Code Online (Sandbox Code Playgroud)

至少差不多......实际上这是相同的[1,1,1] >> return "ok",也就是说>> ["ok"],它会给予

["ok", "ok", "ok"]
Run Code Online (Sandbox Code Playgroud)

如果省略单例return,则每个"ok"都不会被包装在列表中,而是连接在一起,而是字符串本身都是由monadic绑定连接起来的.这就是你得到的"okokok".


等效的默认实现实际上有点不同,但通过-XMonadComprehensions扩展,列表推导确实以这种方式工作.

  • @ user3355020:确定它是一个列表,和任何一样真实.谈论_list monad_只是意味着我们专注于列表的一个特定功能/属性. (4认同)