– это аппликативное значение, а
>xs
– это список, состоящий из них), мы вызываем функцию
>sequenceA
с «хвостом», что возвращает аппликативное значение со списком внутри него. Затем мы просто предваряем значением, содержащимся внутри аппликативного значения
>x
, список, находящийся внутри этого аппликативного значения, – вот именно!
Предположим, мы выполняем:
>sequenceA [Just 1, Just 2]
По определению такая запись эквивалентна следующей:
>(:) <$> Just 1 <*> sequenceA [Just 2]
Разбивая это далее, мы получаем:
>(:) <$> Just 1 <*> ((:) <$> Just 2 <*> sequenceA [])
Мы знаем, что вызов выражения >sequenceA []
оканчивается в виде >Just []
, поэтому данное выражение теперь выглядит следующим образом:
>(:) <$> Just 1 <*> ((:) <$> Just 2 <*> Just [])
что аналогично этому:
>(:) <$> Just 1 <*> Just [2]
…что равно >Just
>[1,2]
!
Другой способ реализации функции >sequenceA
– использование свёртки. Вспомните, что почти любая функция, где мы проходим по списку элемент за элементом и попутно накапливаем результат, может быть реализована с помощью свёртки:
>sequenceA :: (Applicative f) => [f a] –> f [a]
>sequenceA = foldr (liftA2 (:)) (pure [])
Мы проходим список с конца, начиная со значения аккумулятора равного >pure []
. Мы применяем функцию >liftA2 (:)
между аккумулятором и последним элементом списка, что даёт в результате аппликативное значение, содержащее одноэлементный список. Затем мы вызываем функцию >liftA2 (:)
с текущим в данный момент последним элементом и текущим аккумулятором и т. д., до тех пор пока у нас не останется только аккумулятор, который содержит список результатов всех аппликативных значений.
Давайте попробуем применить нашу функцию к каким-нибудь аппликативным значениям:
>ghci> sequenceA [Just 3, Just 2, Just 1]
>Just [3,2,1]
>ghci> sequenceA [Just 3, Nothing, Just 1]
>Nothing
>ghci> sequenceA [(+3),(+2),(+1)] 3
>[6,5,4]
>ghci> sequenceA [[1,2,3],[4,5,6]]
>[[1,4],[1,5],[1,6],[2,4],[2,5],[2,6],[3,4],[3,5],[3,6]]
>ghci> sequenceA [[1,2,3],[4,5,6],[3,4,4],[]]
>[]
При использовании со значениями типа >Maybe
функция >sequenceA
создаёт значение типа >Maybe
, содержащее все результаты в виде списка. Если одно из значений равно >Nothing
, результатом тоже является >Nothing
. Это просто расчудесно, когда у вас есть список значений типа >Maybe
и вы заинтересованы в значениях, только когда ни одно из них не равно >Nothing
!
В применении к функциям >sequenceA
принимает список функций и возвращает функцию, которая возвращает список. В нашем примере мы создали функцию, которая приняла число в качестве параметра и применила его к каждой функции в списке, а затем вернула список результатов. Функция