к значению в узле), и нам просто нужно соединить их. Для этой цели мы используем функцию
>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
с анонимной функцией