[英]How does the List monad work in this example?
The List monad has return x = [x]
. List monad
return x = [x]
。 So why in the following example is the result not [(["a", "b"], [2, 3])]
?那么为什么在下面的例子中结果不是
[(["a", "b"], [2, 3])]
?
> pairs a b = do { x <- a; y <- b; return (x, y)}
> pairs ["a", "b"] [2,3]
[("a",2),("a",3),("b",2),("b",3)]
Let us first analyze and rewrite the function pairs
:让我们首先分析和重写函数
pairs
:
pairs a b = do { x <- a; y <- b; return (x, y)}
Here we thus have a monad.因此,我们有一个 monad。 We use
do
as syntactical sugar.我们使用
do
作为语法糖。 But the compiler rewrites this to:但是编译器将其重写为:
pairs a b = a >>= (\x -> b >>= (\y -> return (x, y)))
Or in a more canonical form:或者以更规范的形式:
pairs a b = (>>=) a (\x -> (>>=) b (\y -> return (x, y)))
Now the list monad is defined as:现在列表 monad 定义为:
instance Monad [] where
return x = [x]
(>>=) xs f = concatMap f xs
So we have written:所以我们写了:
pairs a b = concatMap (\x -> concatMap (\y -> [(x, y)]) b) a
So we thus take as input two lists a
and b
, and we perform a concatMap
on a
with as function (\\x -> concatMap (\\y -> [(x, y)]) b)
.因此,我们将两个列表
a
和b
作为输入,并使用函数(\\x -> concatMap (\\y -> [(x, y)]) b)
在a
上执行concatMap
。 In that function we perform another concatMap
on b
with as function \\y -> [(x, y)]
.在该函数中,我们使用函数
\\y -> [(x, y)]
在b
上执行另一个concatMap
。
So if we evaluate this with pairs ["a", "b"] [2,3]
we get:所以如果我们用
pairs ["a", "b"] [2,3]
评估它,我们得到:
pairs ["a", "b"] [2,3]
-> concatMap (\x -> concatMap (\y -> [(x, y)]) [2,3]) ["a", "b"]
-> concatMap (\y -> [("a", y)]) [2,3] ++ concatMap (\y -> [("b", y)]) [2,3]
-> [("a", 2)] ++ [("a", 3)] ++ [("b", 2)] ++ [("b", 3)]
-> [("a", 2), ("a", 3), ("b", 2), ("b", 3)]
In general,一般来说,
pairs a b = do { x <- a; y <- b; return (x, y) }
= do { x <- a;
do { y <- b;
do { return (x, y) }}}
means, in pseudocode,意味着,在伪代码中,
pairs( a, b) { for x in a do:
for y in b do:
yield( (x, y) );
}
whatever the "for ... in ... do"
and "yield"
mean for the particular monad.无论
"for ... in ... do"
和"yield"
对于特定的单子意味着什么。 More formally, it's更正式地说,它是
= a >>= (\x ->
do { y <- b; -- a >>= k ===
do { return (x, y) }}) -- join (k <$> a)
= join ( (<$> a) -- ( a :: m a
(\x -> -- k :: a -> m b
do { y <- b; -- k <$> a :: m (m b) )
do { return (x, y) }}) ) -- :: m b
( (<$>)
is an alias for fmap
). (
(<$>)
是fmap
的别名)。
For the Identity
monad, where return a = Identity a
and join (Identity (Identity a)) = Identity a
, it is indeed对于
Identity
monad,其中return a = Identity a
和join (Identity (Identity a)) = Identity a
,确实是
pairs( {Identity, a}, {Identity, b}) { x = a;
y = b;
yield( {Identity, {Pair, x, y}} );
}
For the list monad though, "for"
means foreach
, because return x = [x]
and join xs = concat xs
:但是对于列表 monad,
"for"
表示foreach
,因为return x = [x]
并join xs = concat xs
:
-- join :: m (m a) -> m a
-- join :: [] ([] a) -> [] a
-- join :: [[a]] -> [a]
join = concat
and so,所以,
join [ [a1, a2, a3, ...],
[b1, b2, b3, ...],
.....
[z1, z2, z3, ...] ]
=
[ a1, a2, a3, ... ,
b1, b2, b3, ... ,
.....
z1, z2, z3, ... ]
Monadic bind satisfies ma >>= k = join (fmap k ma)
where ma :: ma, k :: a -> mb
for a Monad m
. Monadic 绑定满足
ma >>= k = join (fmap k ma)
其中ma :: ma, k :: a -> mb
对于Monad m
。 Thus for lists, where fmap = map
, we have ma >>= k = join (fmap k ma) = concat (map k ma) = concatMap k ma
:因此对于列表,其中
fmap = map
,我们有ma >>= k = join (fmap k ma) = concat (map k ma) = concatMap k ma
:
m >>= k = [ a, = join [ k a, = join [ [ a1, a2, ... ], = [ a1, a2, ... ,
b, k b, [ b1, b2, ... ], b1, b2, ... ,
c, k c, [ c1, c2, ... ], c1, c2, ... ,
d, k d, [ d1, d2, ... ], d1, d2, ... ,
e, k e, [ e1, e2, ... ], e1, e2, ... ,
... ] >>= k ... ] ............... ] ........... ]
which is exactly what nested loops do.这正是嵌套循环所做的。 Thus
因此
pairs ["a", -- for x in ["a", "b"] do:
"b"] [2, 3] -- for y in [2, 3] do:
= -- yield (x,y)
["a",
"b"] >>= (\x-> join (fmap (\y -> return (x,y)) [2, 3]) )
=
["a",
"b"] >>= (\x-> concat (map (\y -> [ (x,y) ]) [2, 3]) )
=
join [ "a" & (\x-> concat ((\y -> [ (x,y) ]) `map` [2, 3]) ), -- x & f = f x
"b" & (\x-> concat ((\y -> [ (x,y) ]) `map` [2, 3]) ) ]
=
join [ concat ((\y -> [ ("a",y) ]) `map` [2, 3]) ,
concat ((\y -> [ ("b",y) ]) `map` [2, 3]) ]
=
join [ concat [ [("a", 2)], [("a", 3)] ] , -- for y in [2, 3] do: yield ("a",y)
concat [ [("b", 2)], [("b", 3)] ] ] -- for y in [2, 3] do: yield ("b",y)
=
join [ [ ("a", 2) , ("a", 3) ] ,
[ ("b", 2) , ("b", 3) ] ]
=
[ ("a", 2) , ("a", 3) ,
("b", 2) , ("b", 3) ]
Loop unrolling is what nested loops do ⁄ are , and nested computations are the essence of Monad.循环展开是嵌套循环所做的 ⁄是,嵌套计算是 Monad 的本质。
It is also interesting to notice that值得注意的是,
join = = [a1] ++ = [a1] ++ join
[ [ a1, a2, ... ], [ a1, a2, ... ] ++ [a2, ... ] ++ [ [a2, ...],
[ b1, b2, ... ], [ b1, b2, ... ] ++ [ b1, b2, ... ] ++ [ b1, b2, ...],
[ c1, c2, ... ], [ c1, c2, ... ] ++ [ c1, c2, ... ] ++ [ c1, c2, ...],
[ d1, d2, ... ], [ d1, d2, ... ] ++ [ d1, d2, ... ] ++ [ d1, d2, ...],
[ e1, e2, ... ], [ e1, e2, ... ] ++ [ e1, e2, ... ] ++ [ e1, e2, ...],
............... ] ............... ............... .............. ]
which goes to the heart of the "nested loops ⁄ yield" analogy.这是“嵌套循环/产量”类比的核心。 Monads are higher order monoids, "what's the problem?"
单子是高阶幺半群, “有什么问题?”
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.