карта против картыM поведение - PullRequest
31 голосов
/ 29 июня 2010

Я нахожусь в главе ввода / вывода в Real World Haskell. Монады не обсуждаются в книге еще 7 глав. То есть мое понимание ввода / вывода в лучшем случае неполно.

Прямо сейчас я пытаюсь понять функцию mapM. Насколько я понимаю, функция «выполняет» каждый элемент в списке, который должен быть «действием» (монада ввода-вывода).

Что не имеет смысла, так это этот пример . Почему mapM возвращает результат, отличный от map для тех же аргументов?

Prelude> map (\x -> [x]) [0, 1, 2]
[[0],[1],[2]]
Prelude> mapM (\x -> [x]) [0, 1, 2]
[[0,1,2]]

Ответы [ 2 ]

20 голосов
/ 29 июня 2010

Насколько я понимаю, функция «выполняет» каждый элемент в списке, который должен быть «действием» (монадой ввода-вывода).

Это верно для IO, но в вашем примере кода вы не используете монаду IO, вы используете монаду списка (функция, которую вы предоставляете mapM, возвращает список ([x]), а не IO).

mapM определяется как mapM f as = sequence (map f as). Если f возвращает IO, это означает, что для каждого элемента в списке он создает IO, применяя f к элементу. Затем он превращает список IO, которые карта возвращает, в IO, «содержащий» список с использованием последовательности (поэтому, когда вы выполняете IO, вы получаете список, содержащий значения не-IO).

Для списков это означает, что он создает список списков, применяя f к каждому элементу as. Затем он использует sequence для создания списка списков, который содержит все возможные способы занести один элемент каждого списка в списки списков (например, sequence [[1,2],[3,4]] возвращает [[1,3],[1,4],[2,3],[2,4]]).

14 голосов
/ 30 июня 2010

Вероятно, стоит пояснить, что эти два фрагмента не «аналогичны», и вы не должны ожидать связанных результатов.В частности, «монадическая» версия

map (\ x -> [x]) [0, 1, 2]

равна

mapM (\ x -> return [x]) [0, 1, 2]

Обратите внимание на дополнительные return.

В общем, return (map f x)совпадает с mapM (return . f) x.

Это потому, что для монады списка x >>= f «выравнивает» результат применения f к x.Когда вы пропустили return, результаты применения \x -> [x] были сведены в результат.Наличие дополнительного return отменяет дополнительное выравнивание.

...