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

с окончательными результатами выполнения, возвращёнными функциями >(+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 должна помещать значение в минимальный контекст, который по-прежнему возвращает данное значение. И вы могли бы подумать, что бесконечный список чего-либо едва ли является минимальным. Но это имеет смысл при использовании застёгиваемых списков, так как значение должно производиться в каждой позиции. Это также удовлетворяет закону о том, что выражение