>[[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5],[2,4,6]]
>ghci> [[x,y,z] | x <– [1,2], y <– [3,4], z <– [5,6]]
>[[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5],[2,4,6]]
Выражение >(+) <$> [1,2] <*> [4,5,6]
возвращает в результате недетерминированное вычисление >x
>+
>y
, где образец >x
принимает каждое значение из >[1,2]
, а >y
принимает каждое значение из >[4,5,6]
. Мы представляем это в виде списка, который содержит все возможные результаты. Аналогичным образом, когда мы выполняем выражение >sequenceA [[1,2],[3,4],[5,6]]
, результатом является недетерминированное вычисление >[x,y,z]
, где образец >x
принимает каждое значение из >[1,2]
, а >y
– каждое значение из >[3,4]
и т. д. Для представления результата этого недетерминированного вычисления мы используем список, где каждый элемент в списке является одним возможным списком. Вот почему результатом является список списков.
При использовании с действиями ввода-вывода функция >sequenceA
представляет собой то же самое, что и функция >sequence
! Она принимает список действий ввода-вывода и возвращает действие ввода-вывода, которое выполнит каждое из этих действий и в качестве своего результата будет содержать список результатов этих действий ввода-вывода. Так происходит, потому что чтобы превратить значение >[IO a]
в значение >IO [a]
, чтобы создать действие ввода-вывода, возвращающее список результатов при выполнении, все эти действия ввода-вывода должны быть помещены в последовательность, а затем быть выполненными одно за другим, когда потребуется результат выполнения. Вы не можете получить результат действия ввода-вывода, не выполнив его!
Давайте поместим три действия ввода-вывода >getLine
в последовательность:
>ghci> sequenceA [getLine, getLine, getLine]
>эй
>хо
>ух
>["эй","хо","ух"]
В заключение отмечу, что аппликативные функторы не просто интересны, но и полезны. Они позволяют нам объединять разные вычисления – как, например, вычисления с использованием ввода-вывода, недетерминированные вычисления, вычисления, которые могли окончиться неуспешно, и т. д., – используя аппликативный стиль. Просто с помощью операторов ><$>
и ><*>
мы можем применять обычные функции, чтобы единообразно работать с любым количеством аппликативных функторов и использовать преимущества семантики каждого из них.