52700.fb2
Kleisli
мы научились делать три различных операции применения:
Применение:
• обычных функций одного аргумента к специальным значениям (функция +$).
• обычных функций произвольного числа аргументов к специальным значениям (функции +$ и $$)
• специальных функций к специальным значениям (функция *$).
В Haskell для решения этих задач предназначены три отдельных класса. Это функторы, аппликативные
функторы и монады.
Функторы
Посмотрим на определение класса Functor:
class Functor f where
fmap :: (a -> b) -> f a -> f b
Тип метода fmap совпадает с типом для функции +$:
(+$) :: Kleisli m => (a -> b) -> m a -> m b
Нам только нужно заменить m на f и зависимость от Kleisli на зависимость от Functor:
Итак в Haskell у нас есть базовая операция fmap применения обычной функции к значению из мира спе-
циальных функций. В модуле Control.Applicative определён инфиксный синоним <$> для этой функции.
96 | Глава 6: Функторы и монады: теория
Аппликативные функторы
Посмотрим на определение класса Applicative:
class Functor f => Applicative f where
pure
:: a -> f a
(<*> )
:: f (a -> b) -> f a -> f b
Если присмотреться к типам методов этого класса, то мы заметим, что это наши старые знакомые idK и
$$. Если для данного типа f определён экземпляр класса Applicative, то из контекста следует, что для него
также определён и экземпляр класса Functor.
Значит у нас есть функции fmap (или lift1) и <*> (или $$). С их помощью мы можем составить функции
liftN, которые поднимают обычные функции произвольного числа аргументов в мир специальных значений.
Класс Applicative определён в модуле Control.Applicative, там же мы сможем найти и функции liftA,
liftA2, liftA3 и символьный синоним <$> для функции fmap. Функции liftAn определены так:
liftA2 f a b
= f <$> a <*> b
liftA3 f a b c = f <$> a <*> b <*> c
Видно что эти определения с точностью до обозначений совпадают с теми, что мы уже писали для класса
Kleisli.
Монады
Посмотрим на определение класса Monad
class Monad m where
return :: a -> m a
(>>=)
:: m a -> (a -> m b) -> m b
Присмотримся к типам методов этого класса:
return :: a -> m a
Их типа видно, что это ни что иное как функция idK. В классе Monad у неё точно такой же смысл. Теперь
функция >>=, она читается как функция связывания (bind).
(>>=)
:: m a -> (a -> m b) -> m b