为什么 >> 在 haskell 中复制右侧操作数
Why >> duplicates right-hand side operand in haskell
我搜索了一个字符串重复 n
次的解决方案。我从这个solution中找到了duplicate n str = [1..n] >> str
。
我想知道为什么这个方法会重复 str
.
我搜索了 >>
,发现了以下几点:
k >> f = k >>= \_ -> f
和
a >> b >> c >> d
-- is is equivalent to
do a
b
c
d
那我试试这个
ghci> do [1..3]; "a"
"aaa"
但我仍然不明白它是如何工作的。谁能解释这种行为?
列表>>=
的定义是concatMap
:对列表的每个元素应用一个函数,然后连接结果。当您使用 >>
时,这意味着应用一个函数 忽略 列表的每个元素,而不是 returns right-hand 侧的常量值共 >>
[1..3] >> "a" == [1..3] >>= \_ -> "a"
== concatMap (\_ -> "a") [1..3]
== "a" ++ "a" ++ "a"
== "aaa"
根据 Monad 法则,
a >> b >> c >> d
-- is equivalent to
-- (values) (computations)
do a do { a do { _x <- a
b ; b ; _y <- b
c ; c ; _z <- c
d ; r <- d ; r <- d
; return r ; return r
} }
并用 Monad Comprehensions 编写它——对于列表,non-coincidentally,与 List Comprehensions 完全相同——它变成了
[ r | _x <- a, _y <- b, _z <- c, r <- d ]
这意味着,在伪代码中,
for each _x in a: for each _x in a:
for each _y in b: for each _y in b:
for each _z in c: for each _z in c:
for each r in d: do d
do yield r
所以我们只是“做”相同的 d
,一遍又一遍,对于每个 其上方操作的结果 组合 嵌套时尚.
对于列表,这意味着将 d
的元素重复拼接到结果列表中。
在某种意义上广义(嵌套)循环是(单子)/applicative/functors ,描述了从最深层次产生最终结果的组合计算同样的:(*)
Functor Applicative Monad
for x in a: for x in a for x in a:
do yield (foo x) and y in b: for y in (bar x):
do yield (foo x y) do yield (foo x y)
"loop" "loops" "nested loops"
(created on the fly)
(*) 无论有多少层,从整体上看,“循环”组合一个接一个地产生结果,正如每个“循环”产生其枚举在分离,一一。它是如此微不足道,我们甚至不会在命令式循环中注意到它。
每种特定类型的 Functor 都赋予上面的“for”、“in”和“do yield”其含义。对于列表,它意味着拼接结果,通过 concat
/concatMap
.
实现
我搜索了一个字符串重复 n
次的解决方案。我从这个solution中找到了duplicate n str = [1..n] >> str
。
我想知道为什么这个方法会重复 str
.
我搜索了 >>
,发现了以下几点:
k >> f = k >>= \_ -> f
和
a >> b >> c >> d
-- is is equivalent to
do a
b
c
d
那我试试这个
ghci> do [1..3]; "a"
"aaa"
但我仍然不明白它是如何工作的。谁能解释这种行为?
列表>>=
的定义是concatMap
:对列表的每个元素应用一个函数,然后连接结果。当您使用 >>
时,这意味着应用一个函数 忽略 列表的每个元素,而不是 returns right-hand 侧的常量值共 >>
[1..3] >> "a" == [1..3] >>= \_ -> "a"
== concatMap (\_ -> "a") [1..3]
== "a" ++ "a" ++ "a"
== "aaa"
根据 Monad 法则,
a >> b >> c >> d
-- is equivalent to
-- (values) (computations)
do a do { a do { _x <- a
b ; b ; _y <- b
c ; c ; _z <- c
d ; r <- d ; r <- d
; return r ; return r
} }
并用 Monad Comprehensions 编写它——对于列表,non-coincidentally,与 List Comprehensions 完全相同——它变成了
[ r | _x <- a, _y <- b, _z <- c, r <- d ]
这意味着,在伪代码中,
for each _x in a: for each _x in a:
for each _y in b: for each _y in b:
for each _z in c: for each _z in c:
for each r in d: do d
do yield r
所以我们只是“做”相同的 d
,一遍又一遍,对于每个 其上方操作的结果 组合 嵌套时尚.
对于列表,这意味着将 d
的元素重复拼接到结果列表中。
在某种意义上广义(嵌套)循环是(单子)/applicative/functors ,描述了从最深层次产生最终结果的组合计算同样的:(*)
Functor Applicative Monad
for x in a: for x in a for x in a:
do yield (foo x) and y in b: for y in (bar x):
do yield (foo x y) do yield (foo x y)
"loop" "loops" "nested loops"
(created on the fly)
(*) 无论有多少层,从整体上看,“循环”组合一个接一个地产生结果,正如每个“循环”产生其枚举在分离,一一。它是如此微不足道,我们甚至不会在命令式循环中注意到它。
每种特定类型的 Functor 都赋予上面的“for”、“in”和“do yield”其含义。对于列表,它意味着拼接结果,通过 concat
/concatMap
.