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

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

Just 4

*Kleisli> lift2 (+) (Just 2) Nothing

Nothing

Как на счёт функций трёх и более аргументов? У нас уже есть функции lift1 и lift2 определим функцию

lift3:

lift3 :: Kleisli m => (a -> b -> c -> d) -> m a -> m b -> m c -> m d lift3 f a b c = ...

Первые два аргумента мы можем применить с помощью функции lift2. Посмотрим на тип получивше-

гося выражения:

lift2

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

f

:: a -> b -> c -> d

lift2 f a b :: m (c -> d)

-- a’ == a, b’ == b, c’ == c -> d

У нас опять появился тип m (c -> d) и к нему нам нужно применить значение m c, чтобы получить m d.

Этим как раз и занимается функция $$. Итак итоговое определение примет вид:

lift3 :: Kleisli m => (a -> b -> c -> d) -> m a -> m b -> m c -> m d lift3 f a b c = lift2 f a b $$ c

Так мы можем определить любую функцию liftN через функции liftN-1 и $$.

Несколько полезных функций

Теперь мы умеем применять к специальным значениям произвольные обычные функции. Определим ещё

несколько полезных функций. Первая функция принимает список специальных значений и собирает их в

специальный список:

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

import Prelude hiding (id, (>> ), pred, sequence)

sequence :: Kleisli m => [m a] -> m [a]

sequence = foldr (lift2 (:)) (idK [])

Мы “спрячем” из Prelude одноимённую функцию sequence. Посмотрим на примеры:

*Kleisli> sequence [Just 1, Just 2, Just 3]

Just [1,2,3]

*Kleisli> sequence [Just 1, Nothing, Just 3]

Nothing

Во второй команде вся функция вернула Nothing потому что при объединении списка встретилось зна-

чение Nothing, это равносильно тому, что мы объединяем в один список, значения полученные из функций,

которые могут не вычислить результат. Поскольку значение одного из элементов не определено, весь список

не определён.

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

*Kleisli> sequence [[1,2,3], [11,22]]

[[1,11],[1,22],[2,11],[2,22],[3,11],[3,22]]

Она составляет список всех комбинаций элементов из всех подсписков.

С помощью этой функции мы можем определить функцию mapK. Эта функция является аналогом обычной

функции map, но она применяет специальную функцию к списку значений.

mapK :: Kleisli m => (a -> m b) -> [a] -> m [b]

mapK f = sequence . map f

6.4 Функторы и монады

В этой главе мы выписали вручную все определения для класса Kleisli. Мы сделали это потому, что на

самом деле в арсенале стандартных средств Haskell такого класса нет. Класс Kleisli строит замкнутый мир

специальных функций a -> m b. Его цель построить язык в языке и сделать программирование со специ-

альными функциями таким же удобным как и с обычными функциями. Мы пользовались классом Kleisli

исключительно в целях облегчения понимания этого мира. Впрочем никто не мешает нам определить этот

класс и пользоваться им в наших программах.