Изучай Haskell во имя добра! (Липовача) - страница 195

– это аппликативное значение, а >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 принимает список функций и возвращает функцию, которая возвращает список. В нашем примере мы создали функцию, которая приняла число в качестве параметра и применила его к каждой функции в списке, а затем вернула список результатов. Функция