我不知道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]
小心解释一下?为什么列表中的元素数量会影响写入“ok”的次数(或者在最后一种情况下,是否写入数组的次数)? >>算子不应该这样做,是吗?
答案 0 :(得分:12)
首先请注意,这与IO
没有任何关系。它与monad有关,但有一个非常具体的:monad列表。
instance Monad [] where
return x = [x]
f >>= xs = concat $ map f xs -- aka `(>>=) = concatMap`.
最好知道 list comprehensions ,它基本上是语法糖†:
[ result x y z | x <- bla, y <- foo x, z <- bar ]
转换为
bla >>=
\x -> foo x >>=
\y -> bar >>=
\z -> return (result x y z)
现在,a>>b
只是a >>= \_ -> b
的捷径,即它忽略了LHS monadic动作中包含的值,但是“假装”在RHS中使用它们。因此,[1,1,1] >> "ok"
与
[ "ok" | _ <- [1,1,1] ]
至少几乎......实际上与[1,1,1] >> return "ok"
相同,即>> ["ok"]
,这将给出
["ok", "ok", "ok"]
如果省略单例return
,则每个"ok"
都不会被包含在列表中,而是连接在一起,而是字符串本身都是由monadic绑定连接起来的。这就是你如何得到"okokok"
。
† 等效的默认实现实际上有点不同,但使用-XMonadComprehensions
扩展名,列表推导确实以这种方式工作。