52700.fb2 Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 123

Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 123

execWriter :: Writer msg a -> msg

execWriter (Writer (a, msg)) = msg

Первая функция countBiFuns извлекает значение из типов Writer и Sum. А вторая функция countBiFuns’

вычисляет значение.

Мы определили две вспомогательные функции tell, которая записывает сообщение в накопитель и

execWriter, которая возвращает лишь сообщение. Это стандартные для Writer функции.

Посмотрим как работает эта функция:

*Exp> countBiFuns (n 2)

0

*Exp> countBiFuns (n 2 + n 1 + 2 + 3)

3

Накопление результата | 115

Накопление логических значений

В модуле Data.Monoid определены два типа для накопления логических значений. Это типы All и Any. С

помощью типа All мы можем проверить выполняется ли некоторое свойство для всех значений. А с помощью

типа Any мы можем узнать, что существует хотя бы один элемент, для которых это свойство выполнено.

Посмотрим на определение экземпляров класса Monoid для этих типов:

newtype All = All { getAll :: Bool }

instance Monoid All where

mempty = All True

All x ‘mappend‘ All y = All (x && y)

В типе All мы накапливаем значения с помощью логического “и”. Нейтральным элементом является кон-

структор True. Итоговое значение накопителя будет равно True только в том случае, если все накапливаемые

сообщения были равны True.

В типе Any всё наоборот:

instance Monoid Any where

mempty = Any False

Any x ‘mappend‘ Any y = Any (x || y)

Посмотрим как работают эти типы. Составим функцию, которая проверяет отсутствие оператора минус

в выражении:

noNeg :: Exp -> Bool

noNeg = not . getAny . execWriter . anyNeg

anyNeg :: Exp -> Writer Any ()

anyNeg x = case x of

Neg _

-> tell (Any True)

Add a b -> bi a b

Mul a b -> bi a b

_

-> pure ()

where bi a b = anyNeg a *> anyNeg b

Функция anyNeg проверяет есть ли в выражении хотя бы один конструктор Neg. В функции noNeg мы

извлекаем результат и берём его отрицание, чтобы убедиться в том что в выражении не встретилось ни

одного конструктора Neg.

*Exp> noNeg (n 2 + n 1 + 2 + 3)

True

*Exp> noNeg (n 2 - n 1 + 2 + 3)

False

Накопление списков

Экземпляр класса Monoid определён и для списков. Предположим у нас есть дерево, в каждом узле кото-