>> 运算符 - Haskell 中的穷人循环?
>> operator - poor man's loop in Haskell?
我不知道 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" 被写入的次数(或者在最后一种情况下,数组被写入的次数)? >> 运算符不应该这样做,是吗?
首先请注意,这与 IO
没有任何关系。它与单子有关,但与一个非常具体的单子有关:列表单子。
instance Monad [] where
return x = [x]
f >>= xs = concat $ map f xs -- aka `(>>=) = concatMap`.
最好知道列表理解,它基本上是语法糖†:
[ 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
扩展,列表理解确实以这种方式工作。
我不知道 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" 被写入的次数(或者在最后一种情况下,数组被写入的次数)? >> 运算符不应该这样做,是吗?
首先请注意,这与 IO
没有任何关系。它与单子有关,但与一个非常具体的单子有关:列表单子。
instance Monad [] where
return x = [x]
f >>= xs = concat $ map f xs -- aka `(>>=) = concatMap`.
最好知道列表理解,它基本上是语法糖†:
[ 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
扩展,列表理解确实以这种方式工作。