List 在本例中,列表monad是如何工作的?
列表monad有List 在本例中,列表monad是如何工作的?,list,haskell,monads,do-notation,List,Haskell,Monads,Do Notation,列表monad有返回x=[x]。那么,为什么在下面的示例中结果不是[([“a”,“b”],[2,3])] >pairs a b=do{x让我们首先分析并重写函数pairs: pairs a b = do { x <- a; y <- b; return (x, y)} 或者以更规范的形式: pairs a b = (>>=) a (\x -> (>>=) b (\y -> return (x, y))) 现在,列表monad定义为: insta
返回x=[x]
。那么,为什么在下面的示例中结果不是[([“a”,“b”],[2,3])]
>pairs a b=do{x让我们首先分析并重写函数pairs
:
pairs a b = do { x <- a; y <- b; return (x, y)}
或者以更规范的形式:
pairs a b = (>>=) a (\x -> (>>=) b (\y -> return (x, y)))
现在,列表monad定义为:
instance Monad [] where
return x = [x]
(>>=) xs f = concatMap f xs
所以我们写了:
pairs a b = concatMap (\x -> concatMap (\y -> [(x, y)]) b) a
因此,我们将两个列表a
和b
作为输入,对a
执行concatMap
,使用as函数(\x->concatMap(\y->[(x,y)])b
。在该函数中,我们对b
执行另一个concatMap
,使用as函数\y->[(x,y)]
因此,如果我们使用对[“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)]
总的来说
pairs a b = do { x <- a; y <- b; return (x, y) }
= do { x <- a;
do { y <- b;
do { return (x, y) }}}
无论对于特定单子而言,“for…in…do”
和“yield”
意味着什么。更正式地说,它是
= 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
但是对于列表monad,“For”
意味着foreach
,因为返回x=[x]
和连接xs=concat xs
:
-- join :: m (m a) -> m a
-- join :: [] ([] a) -> [] a
-- join :: [[a]] -> [a]
join = concat
所以,
join [ [a1, a2, a3, ...],
[b1, b2, b3, ...],
.....
[z1, z2, z3, ...] ]
=
[ a1, a2, a3, ... ,
b1, b2, b3, ... ,
.....
z1, z2, z3, ... ]
一元绑定满足ma>=k=join(fmap kma)
其中ma::ma,k::a->mb
对于Monad m
。因此对于fmap=map
的列表,我们有ma>=k=join(fmap kma)=concat(map kma)=concatMap kma
:
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 ... ] ............... ] ........... ]
这正是嵌套循环所做的
循环展开是嵌套循环所做的⁄是,嵌套计算是Monad的本质
注意到这一点也很有趣
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, ...],
............... ] ............... ............... .............. ]
这是“嵌套循环⁄yield”类比的核心。单子是高阶幺半群,“有什么问题吗?”因为-列表单子还有一个(>>=)=concatMap
绑定操作,您隐式地使用它与(您了解绑定是如何工作的吗?因为返回
有一个参数(x,y)
,因此它产生[(x,y)]
成对=返回
将提供您的期望值。@chepner(您的意思是成对=curry返回
)谢谢您的解释。我的困惑是
-- join :: m (m a) -> m a
-- join :: [] ([] a) -> [] a
-- join :: [[a]] -> [a]
join = concat
join [ [a1, a2, a3, ...],
[b1, b2, b3, ...],
.....
[z1, z2, z3, ...] ]
=
[ a1, a2, a3, ... ,
b1, b2, b3, ... ,
.....
z1, z2, z3, ... ]
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 ... ] ............... ] ........... ]
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) ]
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, ...],
............... ] ............... ............... .............. ]