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

. Сначала эта функция проецируется на наше дерево; каждый элемент становится одноэлементным списком. Действие функции >mappend, которое имеет место между всеми этими одноэлементными списками, возвращает в результате один список, содержащий все элементы нашего дерева:

>ghci> F.foldMap (\x –> [x]) testTree

>[1,3,6,5,8,9,10]

Самое классное, что все эти трюки не ограничиваются деревьями. Они применимы ко всем экземплярам класса >Foldable!

13

Пригоршня монад

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

В этой главе вы узнаете о монадах, которые, по сути, представляют собой расширенные аппликативные функторы, так же как аппликативные функторы являются всего лишь расширенными функторами.

Совершенствуем наши аппликативные функторы


Когда мы начали с функторов, вы видели, что можно отображать разные типы данных с помощью функций, используя класс типов >Functor. Введение в функторы заставило нас задаться вопросом: «Когда у нас есть функция типа >a –> b и некоторый тип данных >f a, как отобразить этот тип данных с помощью функции, чтобы получить значение типа >f b?» Вы видели, как с помощью чего-либо отобразить >Maybe a, список >[a], >IO a и т. д. Вы даже видели, как с помощью функции типа >a –> b отобразить другие функции типа >r –> a, чтобы получить функции типа >r –> b. Чтобы ответить на вопрос о том, как отобразить некий тип данных с помощью функции, нам достаточно было взглянуть на тип функции >fmap:

>fmap :: (Functor f) => (a –> b) –> f a –> f b

А затем нам необходимо было просто заставить его работать с нашим типом данных, написав соответствующий экземпляр класса >Functor.

Потом вы узнали, что возможно усовершенствование функторов, и у вас возникло ещё несколько вопросов. Что если эта функция типа >a –> b уже обёрнута в значение функтора? Скажем, у нас есть >Just (*3) – как применить это к значению >Just 5? Или, может быть, не к >Just 5, а к значению >Nothing? Или, если у нас есть список >[(*2),(+4)], как применить его к списку >[1,2,3]? Как это вообще может работать?.. Для этого был введён класс типов >Applicative:

>(<*>) :: (Applicative f) => f (a –> b) –> f a –> f b

Вы также видели, что можно взять обычное значение и обернуть его в тип данных. Например, мы можем взять значение