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

Поведение карты и карты

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

Сейчас я пытаюсь понять функцию mapM. Как я понимаю, функция "выполняет" каждый элемент в списке, который должен быть "действием" (IO monad).

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

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

Ответ 1

Как я понимаю, функция "выполняет" каждый элемент в списке, который должен быть "действием" (IO monad).

Это верно для 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]]).

Ответ 2

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

map (\ x → [x]) [0, 1, 2]

является

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

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

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

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