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

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

>ghci> lengthCompare "ямб" "абыр"

>LT

>ghci> lengthCompare "ямб" "абы"

>LT

>ghci> lengthCompare "ямб" "абр"

>GT

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

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

Моноид Maybe

Рассмотрим несколько способов, которыми для типа >Maybe a могут быть определены экземпляры класса >Monoid, и обсудим, чем эти экземпляры полезны.

Один из способов состоит в том, чтобы обрабатывать тип >Maybe a как моноид, только если его параметр типа >a тоже является моноидом, а потом реализовать функцию >mappend так, чтобы она использовала операцию >mappend для значений, обёрнутых в конструктор >Just. Мы используем значение >Nothing как единичное, и поэтому если одно из двух значений, которые мы объединяем с помощью функции >mappend, равно >Nothing, мы оставляем другое значение. Вот объявление экземпляра:

>instance Monoid a => Monoid (Maybe a) where

>   mempty = Nothing

>   Nothing `mappend` m = m

>   m `mappend` Nothing = m

>   Just m1 `mappend` Just m2 = Just (m1 `mappend` m2)

Обратите внимание на ограничение класса. Оно говорит, что тип >Maybe является моноидом, только если для типа >a определён экземпляр класса >Monoid. Если мы объединяем нечто со значением >Nothing, используя функцию >mappend, результатом является это нечто. Если мы объединяем два значения >Just с помощью функции >mappend, то содержимое значений >Just объединяется с помощью этой функции, а затем оборачивается обратно в конструктор >Just. Мы можем делать это, поскольку ограничение класса гарантирует, что тип значения, которое находится внутри >Just, имеет экземпляр класса >Monoid.

>ghci> Nothing `mappend` Just "андрей"

>Just "андрей"

>ghci> Just LT `mappend` Nothing

>Just LT

>ghci> Just (Sum 3) `mappend` Just (Sum 4)

>Just (Sum {getSum = 7})

Это полезно, когда мы имеем дело с моноидами как с результатами вычислений, которые могли окончиться неуспешно. Из-за наличия этого экземпляра нам не нужно проверять, окончились ли вычисления неуспешно, определяя, вернули они значение