簡體   English   中英

List monad 在這個例子中是如何工作的?

[英]How does the List monad work in this example?

List monad return x = [x] 那么為什么在下面的例子中結果不是[(["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)]

讓我們首先分析和重寫函數pairs

pairs a b = do { x <- a; y <- b; return (x, y)}

因此,我們有一個 monad。 我們使用do作為語法糖。 但是編譯器將其重寫為:

pairs a b = a >>= (\x -> b >>= (\y -> 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

因此,我們將兩個列表ab作為輸入,並使用函數(\\x -> concatMap (\\y -> [(x, y)]) b)a上執行concatMap 在該函數中,我們使用函數\\y -> [(x, y)]b上執行另一個concatMap

所以如果我們用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)]

一般來說,

pairs a b = do { x <- a; y <- b; return (x, y) }  
          = do { x <- a;
                    do { y <- b; 
                            do { return (x, y) }}}

意味着,在偽代碼中,

pairs( a, b) {  for x in a do: 
                     for y in b do: 
                                 yield( (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

(<$>)fmap的別名)。

對於Identity monad,其中return a = Identity ajoin (Identity (Identity a)) = Identity a ,確實是

pairs( {Identity, a}, {Identity, b}) {  x = a; 
                                        y = b; 
                                        yield( {Identity, {Pair, x, y}} ); 
                                     }

但是對於列表 monad, "for"表示foreach ,因為return x = [x]join 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, ...  ]

Monadic 綁定滿足ma >>= k = join (fmap k ma)其中ma :: ma, k :: a -> mb對於Monad m 因此對於列表,其中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         ...  ]          ...............  ]      ...........   ]

這正是嵌套循環所做的。 因此

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)    ]

循環展開是嵌套循環所做的 ⁄嵌套計算是 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, ...],
    ............... ]   ...............        ...............         ..............  ]

這是“嵌套循環/產量”類比的核心。 單子是高階幺半群, “有什么問題?”

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM