с окончательными результатами выполнения, возвращёнными функциями
>(+3)
,
>(*2)
и
>(/2)
. Значение
>5
передаётся каждой из трёх функций, а затем с этими результатами вызывается анонимная функция
>\x y z –> [x, y, z]
.
ПРИМЕЧАНИЕ. Не так уж важно, поняли ли вы, как работает экземпляр типа >(–>) r
для класса >Applicative
, так что не отчаивайтесь, если вам это пока не ясно. Поработайте с аппликативным стилем и функциями, чтобы получить некоторое представление о том, как использовать функции в качестве аппликативных функторов.
Оказывается, есть и другие способы для списков быть аппликативными функторами. Один способ мы уже рассмотрели: вызов оператора ><*>
со списком функций и списком значений, который возвращает список всех возможных комбинаций применения функций из левого списка к значениям в списке справа.
Например, если мы выполним >[(+3),(*2)] <*> [1,2]
, то функция >(+3)
будет применена и к >1,
и к >2
; функция >(*2)
также будет применена и к >1
, и к >2
, а результатом станет список из четырёх элементов: >[4,5,2,4]
. Однако >[(+3),(*2)] <*> [1,2]
могла бы работать и таким образом, чтобы первая функция в списке слева была применена к первому значению в списке справа, вторая была бы применена ко второму значению и т. д. Это вернуло бы список с двумя значениями: >[4,4]
. Вы могли бы представить его как >[1 + 3, 2 * 2]
.
Экземпляром класса >Applicative
, с которым мы ещё не встречались, является тип >ZipList
, и находится он в модуле >Control.Applicative
.
Поскольку один тип не может иметь два экземпляра для одного и того же класса типов, был введён тип >ZipList a
, в котором имеется один конструктор (>ZipList
) с единственным полем (список). Вот так определяется его экземпляр:
>instance Applicative ZipList where
> pure x = ZipList (repeat x)
> ZipList fs <*> ZipList xs = ZipList (zipWith (\f x –> f x) fs xs)
Оператор ><*>
применяет первую функцию к первому значению, вторую функцию – ко второму значению, и т. д. Это делается с помощью выражения >zipWith (\f x –> f x) fs xs
. Ввиду особенностей работы функции >zipWith
окончательный список будет той же длины, что и более короткий список из двух.
Функция >pure
здесь также интересна. Она берёт значение и помещает его в список, в котором это значение просто повторяется бесконечно. Выражение >pure "ха-ха"
вернёт >ZipList (["ха-ха","ха-ха","ха-ха"…
Это могло бы сбить с толку, поскольку вы узнали, что функция >pure
должна помещать значение в минимальный контекст, который по-прежнему возвращает данное значение. И вы могли бы подумать, что бесконечный список чего-либо едва ли является минимальным. Но это имеет смысл при использовании застёгиваемых списков, так как значение должно производиться в каждой позиции. Это также удовлетворяет закону о том, что выражение