2013-02-19 44 views
12

我想我明白列表monad但後來我發現我不是。這是故事。是(>>)應該放棄所有左側輸出嗎?

定列表m和功能k

> let m = [1..10] 
> :t m 
m :: [Integer] 

> let k = replicate 2 
> :t k 
k :: a -> [a] 

與綁定>>=播放給我的期望

> :t (>>=) 
(>>=) :: Monad m => m a -> (a -> m b) -> m b 
> :t m >>= k 
m >>= k :: [Integer] 
> m >>= k 
[1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10] 

>>

預期(從IO單子,一切都在經歷上留下方將被丟棄)

m >> m 
[1,2,3,4,5,6,7,8,9,10] 

得到

> :t (>>) 
(>>) :: Monad m => m a -> m b -> m b 
:t m >> m 
m >> m :: [Integer] 
> m >> m 
[1,2,3,4,5,6,7,8,9,10,1,2,3,4,5 ... 9,10] -- truncated, real output is 100 elements 

請解釋爲什麼>>沒有表現得像我預期(當然我必須有誤解),什麼是解釋>>正確的方法是什麼?

回答

25

(>>)丟棄從它的第一個參數,但沒有影響。在這種情況下,它可能會更容易看到,如果你使用列表不同類型:

λ> "ab" >> [1,2,3,4] 
[1,2,3,4,1,2,3,4] 

注意如何第一個列表的值都不會被使用。

請記住(>>)的定義:a >> b = a >>= (\_ -> b)。所以這變成"ab" >>= (\_ -> [1,2,3,4]),即concat (map (\_ -> [1,2,3,4]) ['a','b']),即concat [[1,2,3,4],[1,2,3,4]](也是,[i | _ <- "ab", i <- [1,2,3,4]])。

With [](>>=)表示類似於「for each」。右側的函數作爲左側每個值的參數。因此,丟棄值的(>>)仍然意味着「對於每個」 - 但是這次它不能使用該值,因此它意味着「第二個列表的元素,重複次數與第一個列表中的元素一樣多」。

+0

哇!多麼清楚(而且非常快)的答案。謝謝 – wizzup 2013-02-19 09:16:13

12

foo >> barfoo >>= \_ -> bar相同。所以在IO的情況下,它執行左邊的動作,忽略該動作的返回值,然後執行正確的動作。在列表的情況下,它將映射到左列表中的每個元素上,忽略每個元素的值,並在每個點處插入正確的列表。

看它的另一種方式是,對於>>=名單相同flip concatMap>>是一樣的flip (concatMap . const)

+0

非常感謝,我只能選擇一個可接受的答案。 – wizzup 2013-02-19 09:18:22

相關問題