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

к значению в узле), и нам просто нужно соединить их. Для этой цели мы используем функцию >mappend, и естественным образом левое поддерево идёт первым, затем – значение узла, а потом – правое поддерево[14].



Обратите внимание, что нам не нужно было предоставлять функцию, которая принимает значение и возвращает моноидное значение. Мы принимаем эту функцию как параметр к >foldMap, и всё, что нам нужно решить, – это где применить эту функцию и как соединить результирующие моноиды, которые она возвращает.

Теперь, когда у нас есть экземпляр класса >Foldable для нашего типа, представляющего дерево, мы получаем функции >foldr и >foldl даром! Рассмотрите вот это дерево:

>testTree = Node 5

>            (Node 3

>               (Node 1 EmptyTree EmptyTree)

>               (Node 6 EmptyTree EmptyTree)

>            )

>            (Node 9

>               (Node 8 EmptyTree EmptyTree)

>               (Node 10 EmptyTree EmptyTree)

>            )

У него значение >5 в качестве его корня, а его левый узел содержит значение >3 со значениями >1 слева и >6 справа. Правый узел корня содержит значение >9, а затем значения >8 слева от него и >10 в самой дальней части справа. Используя экземпляр класса >Foldable, мы можем производить всё те же свёртки, что и над списками:

>ghci> F.foldl (+) 0 testTree

>42

>ghci> F.foldl (*) 1 testTree

>64800

Функция >foldMap полезна не только для создания новых экземпляров класса >Foldable. Она также очень удобна для превращения нашей структуры в одно моноидное значение. Например, если мы хотим узнать, равно ли какое-либо из чисел нашего дерева >3, мы можем сделать следующее:

>ghci> getAny $ F.foldMap (\x –> Any $ x == 3) testTree

>True

Здесь анонимная функция >\x –> Any $ x == 3 – это функция, которая принимает число и возвращает моноидное значение: значение >Bool, обёрнутое в тип >Any. Функция >foldMap применяет эту функцию к каждому элементу нашего дерева, а затем превращает получившиеся моноиды в один моноид с помощью вызова функции >mappend. Предположим, мы выполняем следующее:

>ghci> getAny $ F.foldMap (\x –> Any $ x > 15) testTree

>False

Все узлы нашего дерева будут содержать значение >Any False после того, как к ним будет применена анонимная функция. Но чтобы получить в итоге значение >True, реализация функции >mappend для типа >Any должна принять по крайней мере одно значение >True в качестве параметра. Поэтому окончательным результатом будет >False, что логично, поскольку ни одно значение в нашем дереве не превышает >15.

Мы также можем легко превратить наше дерево в список, просто используя функцию >foldMap с анонимной функцией