(>>)是否应该丢弃所有左侧输出?

时间:2013-02-19 08:33:48

标签: list haskell monads

我想我确实理解列表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 monad体验,左侧的所有内容都将被丢弃)

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

GOT

> :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

请解释为什么>>的行为不符合我的预期(当然我必须有误解)以及解释>>的正确方法是什么?

2 个答案:

答案 0 :(得分: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]])。

使用[](>>=)表示类似“为每个人”的内容。右边的函数作为参数得到左边的每个值。所以丢弃值的(>>)仍然意味着“为每个” - 但这次它不能使用该值,所以它只是意味着“第二个列表的元素,重复次数与元素一样多”在第一个列表“。

答案 1 :(得分:12)

foo >> barfoo >>= \_ -> bar相同。因此,在IO的情况下,它执行左操作,忽略该操作的返回值,然后执行正确的操作。对于列表,它映射左侧列表中的每个元素,忽略每个元素的值,并在每个点插入右侧列表。

查看它的另一种方法是列表的>>=flip concatMap相同,>>flip (concatMap . const)相同。