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

.

Когда вы отображаете функтор с помощью функции при использовании обычных функторов, вы не можете извлечь результат каким-либо общим способом, даже если результатом является частично применённая функция. Аппликативные функторы, с другой стороны, позволяют вам работать с несколькими функторами, используя одну функцию.

Аппликативный стиль

При использовании класса типов >Applicative мы можем последовательно задействовать несколько операторов ><*> в виде цепочки вызовов, что позволяет легко работать сразу с несколькими аппликативными значениями, а не только с одним. Взгляните, например, на это:

>ghci> pure (+) <*> Just 3 <*> Just 5

>Just 8

>ghci> pure (+) <*> Just 3 <*> Nothing

>Nothing

>ghci> pure (+) <*> Nothing <*> Just 5

>Nothing

Мы обернули оператор >+ в аппликативное значение, а затем использовали оператор ><*>, чтобы вызвать его с двумя параметрами, оба из которых являются аппликативными значениями.



Давайте посмотрим, как это происходит, шаг за шагом. Оператор ><*> левоассоциативен; это значит, что

>pure (+) <*> Just 3 <*> Just 5

то же самое, что и вот это:

>(pure (+) <*> Just 3) <*> Just 5

Сначала оператор >+ помещается в аппликативное значение – в данном случае значение типа >Maybe, которое содержит функцию. Итак, у нас есть >pure (+), что, по сути, равно >Just (+). Далее происходит вызов >Just (+) <*> Just 3. Его результатом является >Just (3+). Это из-за частичного применения. Применение только значения >3 к оператору >+ возвращает в результате функцию, которая принимает один параметр и добавляет к нему >3. Наконец, выполняется >Just (3+) <*> Just 5, что в результате возвращает >Just 8.

Ну разве не здорово?! Аппликативные функторы и аппликативный стиль вычисления >pure f <*> x <*> y <*> … позволяют взять функцию, которая ожидает параметры, не являющиеся аппликативными значениями, и использовать эту функцию для работы с несколькими аппликативными значениями. Функция может принимать столько параметров, сколько мы захотим, потому что она всегда частично применяется шаг за шагом между вхождениями оператора ><*>.

Это становится ещё более удобным и очевидным, если мы примем во внимание тот факт, что выражение >pure f <*> x равно >fmap f x. Это один из законов аппликативных функторов, которые мы более подробно рассмотрим чуть позже; но давайте подумаем, как он применяется здесь. Функция >pure помещает значение в контекст по умолчанию. Если мы просто поместим функцию в контекст по умолчанию, а затем извлечём её и применим к значению внутри другого аппликативного функтора, это будет то же самое, что просто отобразить этот аппликативный функтор с помощью данной функции. Вместо записи