Подтвердить что ты не робот

Is (>>) должен отбросить весь левый выход?

Я думаю, что понимаю сборник монады, но потом обнаружил, что нет. Вот история.

Данный список 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

Пожалуйста, объясните, почему >> не ведет себя так, как я ожидал (конечно, должно быть, недоразумение) и каков правильный способ интерпретации >>?

4b9b3361

Ответ 1

(>>) отбрасывает значения из первого аргумента, но не эффекты. В этом случае было бы легче увидеть, используете ли вы списки с разными типами:

λ> "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]]).

С [], (>>=) означает что-то вроде "для каждого". Функция справа получает в качестве аргумента каждое значение слева. Поэтому (>>), который отбрасывает значения, по-прежнему означает "для каждого", но на этот раз он не может использовать значение, поэтому он просто означает "элементы второго списка, повторяющиеся столько раз, сколько есть элементов в первый список".

Ответ 2

foo >> bar совпадает с foo >>= \_ -> bar. Таким образом, в случае IO он выполняет левое действие, игнорируя возвращаемое значение этого действия, а затем выполняет правильное действие. В случае списков он отображает каждый элемент в левом списке, игнорируя значение каждого элемента и вставляя правый список в каждой точке.

Другим способом взглянуть на это является то, что >>= для списков совпадает с flip concatMap, >> совпадает с flip (concatMap . const).