ворачивает значение в конструктор Just.
instance Kleisli Maybe where
idK
= Just
f *>g =\a -> casef a of
Nothing -> Nothing
Justb
->g b
Смотрите, в case-выражении мы возвращаем Nothing, если функция f вернула Nothing, а если ей удалось
вычислить значение и она вернула ( Justb) мы передаём это значение в следующую функцию, то есть
составляем выражение (g b).
Сохраним это определение в модуле Kleisli, а также определение для функции pred и загрузим модуль
в интерпретатор. Перед этим нам придётся добавить в список функций, которые мы не хотим импортировать
из Preludeфункцию pred, она также уже определена в Prelude. Для определения нашей функции нам по-
требуется модуль Nat, который мы уже определили. Скопируем файл Nat.hs в ту же директорию, в которой
содержится файл Kleisli.hs и подключим этот модуль. Шапка модуля примет вид:
Примеры специальных функций | 89
a
f
b
b
g
c
Nothing
Nothing
b
a
g
f
c
Nothing
a
f*>g
c
Nothing
Рис. 6.3: Композиция частично определённых функций
module Kleisli where
import Preludehiding(id, ( >>), pred)
import Nat
Добавим определение экземпляра Kleisliдля Maybeв модуль Kleisliа также определение функции
pred. Сохраним обновлённый модуль и загрузим в интерпретатор.
*Kleisli> :load Kleisli
[1 of2] Compiling Nat
( Nat.hs, interpreted )
[2 of2] Compiling Kleisli
( Kleisli.hs, interpreted )
Ok, modules loaded : Kleisli, Nat.
*Kleisli> letpred2 =pred *>pred
*Kleisli> letpred3 =pred *>pred *>pred
*Kleisli> lettwo
= Succ( Succ Zero)
*Kleisli>
*Kleisli>pred two
Just( Succ Zero)
*Kleisli>pred3 two
Nothing
Обратите внимание на то, как легко определяются производные функции. Желаемое поведение для ча-
стично определённых функций закодировано в функции ( *>) теперь нам не нужно заворачивать значения и
разворачивать их из типа Maybe.
Приведём пример функции, которая составлена из частично определённой функции и обычной. Опреде-
лим функцию beside, которая вычисляет соседей для данного числа Пеано.
*Kleisli> letbeside =pred +>\a ->(a, a +2)
*Kleisli>beside Zero
Nothing
*Kleisli>beside two
Just( Succ Zero, Succ( Succ( Succ Zero)))
*Kleisli>(pred *>beside) two
Just( Zero, Succ( Succ Zero))
В выражении
pred +>\a ->(a, a +2)
Мы сначала вычисляем предыдущее число, и если оно есть составляем пару из \a ->(a, a +2), в пару
попадёт данное число и число, следующее за ним через одно. Поскольку сначала мы вычислили предыдущее
число в итоговом кортеже окажется предыдущее число и следующее.
90 | Глава 6: Функторы и монады: теория
Итак с помощью функций из класса Kleisliмы можем составлять частично определённые функции в
бесточечном стиле. Обратите внимание на то, что все функции кроме pred были составлены в интерпрета-
торе.Отметим, что в Preludeопределена специальная функция maybe, которая похожа на функцию foldr для
списков, она заменяет в значении типа Maybeконструкторы на функции. Посмотрим на её определение:
maybe
::b ->(a ->b) -> Maybea ->b
maybe n f Nothing
=
n
maybe n f ( Justx) =
f x
С помощью этой функции мы можем переписать определение экземпляра Kleisliтак:
instance Kleisli Maybe where
idM
= Just
f *>g
=f >>maybe Nothingg
Многозначные функции
Многозначные функции ветрены и непостоянны. Для некоторых значений аргументов они возвращают
одно значение, для иных десять, а для третьих и вовсе ничего. В Haskell такие функции имеют тип a ->[b].
Функция возвращает список ответов. На (рис. 6.4) изображена схема многозначной функции.
a
f
b
Рис. 6.4: Многозначная функция
Приведём пример. Системы Линденмайера (или L-системы) моделируют развитие живого организма.
Считается, что организм состоит из последовательности букв (или клеток). В каждый момент времени одна
Читать дальше