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

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

(+$) :: (a -> b)

-> m a -> m b

Функция *$ применяет специальную функцию к специальному значению, а функция +$ применяет обыч-

ную функцию к специальному значению. Определения выглядят также как и в случае обычной функции

применения, мы только меняем знаки для композиции:

f

$ a = (const a >> f) ()

f *$ a = (const a *> f) ()

f +$ a = (const a +> f) ()

Теперь мы можем не только нанизывать специальные функции друг на друга но и применять их к значе-

ниям. Добавим эти определения в модуль Kleisli и посмотрим как происходит применение в интерпрета-

торе. Одна тонкость заключается в том, что мы определяли применение в терминах класса Kleisli, поэтому

правильно было написать типы новых функций так:

infixr 0 +$, *$

(*$) :: Kleisli m => (a -> m b) -> m a -> m b

(+$) :: Kleisli m => (a -> b)

-> m a -> m b

Также мы определили приоритет выполнения операций.

Загрузим в интерпретатор:

*Kleisli> let three = Succ (Succ (Succ Zero))

*Kleisli> pred *$ pred *$ idK three

Just (Succ Zero)

*Kleisli> pred *$ pred *$ idK Zero

Nothing

Применение функций | 93

Обратите внимание на то как мы погружаем в мир специальных функций обычное значение с помощью

функции idK.

Вычислим третье поколение L-системы:

*Kleisli> next *$ next *$ next *$ idK ’a’

”abaab”

Мы можем использовать и другие функции на списках:

*Kleisli> next *$ tail $ next *$ reverse $ next *$ idK ’a’

”aba”

Применение функций многих переменных

С помощью функции +$ мы можем применять к специальным значениям обычные функции одного аргу-

мента. А что если нам захочется применить функцию двух аргументов?

Например если мы захотим сложить два частично определённых числа:

?? (+) (Just 2) (Just 2)

На месте ?? должна стоять функция типа:

?? :: (a -> b -> c) -> m a -> m b -> m c

Оказывается с помощью методов класса Kleisli мы можем определить такую функцию для любой обыч-

ной функции, а не только для функции двух аргументов. Мы будем называть такие функции словом liftN,

где N – число, указывающее на арность функции. Функция (liftN f) “поднимает” (от англ. lift) обычную

функцию f в мир специальных функций.

Функция lift1 у нас уже есть, это просто функция +$. Теперь давайте определим функцию lift2:

lift2 :: Kleisli m => (a -> b -> c) -> m a -> m b -> m c

lift2 f a b = ...

Поскольку функция двух аргументов на самом деле является функцией одного аргумента мы можем

применить первый аргумент с помощью функции lift1, посмотрим что у нас получится:

lift1