…, мы можем написать
>fmap
>f
>x
><*>
>y
><*>
… Вот почему модуль
>Control.Applicative
экспортирует оператор, названный
><$>
, который является просто синонимом функции
>fmap
в виде инфиксного оператора. Вот как он определён:
>(<$>) :: (Functor f) => (a –> b) –> f a –> f b
>f <$> x = fmap f x
ПРИМЕЧАНИЕ. Вспомните, что переменные типов не зависят от имён параметров или имён других значений. Здесь идентификатор >f
в сигнатуре функции является переменной типа с ограничением класса, которое говорит, что любой конструктор типа, который заменяет >f
, должен иметь экземпляр класса >Functor
. Идентификатор >f
в теле функции обозначает функцию, с помощью которой мы отображаем значение >x
. Тот факт, что мы использовали >f
для представления обеих вещей, не означает, что они представляют одну и ту же вещь.
При использовании оператора ><$>
аппликативный стиль проявляет себя во всей красе, потому что теперь, если мы хотим применить функцию >f
к трем аппликативным значениям, можно просто написать >f <$> x <*> y <*> z
. Если бы параметры были обычными значениями, мы бы написали >f x y z
.
Давайте подробнее рассмотрим, как это работает. Предположим, что мы хотим соединить значения >Just "johntra"
и >Just "volta"
в одну строку, находящуюся внутри функтора >Maybe
. Сделать это вполне в наших силах!
>ghci> (++) <$> Just "johntra" <*>
>Just "volta" Just "johntravolta"
Прежде чем мы увидим, что происходит, сравните предыдущую строку со следующей:
>ghci> (++) "johntra" "volta"
>"johntravolta"
Чтобы использовать обычную функцию с аппликативным функтором, просто разбросайте вокруг несколько ><$>
и ><*>
, и функция будет работать с аппликативными значениями и возвращать аппликативное значение. Ну не здорово ли?
Возвратимся к нашему выражению >(++) <$> Just "джонтра" <*> Just "волта"
: сначала оператор >(++)
, который имеет тип >(++) :: [a] – > [a] –> [a]
, отображает значение >Just "джонтра"
. Это даёт в результате такое же значение, как >Just ("джонтра"++)
, имеющее тип >Maybe ([Char] –> [Char])
. Заметьте, как первый параметр оператора >(++)
был «съеден» и идентификатор >a
превратился в тип >[Char]
! А теперь выполняется выражение >Just ("джонтра"++) <*> Just "волта"
, которое извлекает функцию из >Just
и отображает с её помощью значение >Just "волта"
, что в результате даёт новое значение – >Just "джонтраволта"
. Если бы одним из двух значений было значение >Nothing
, результатом также было бы >Nothing
.