. Функция
>ap
, по существу, – это
><*>,
только с ограничением
>Monad
, а не
>Applicative
. Вот её определение:
>ap :: (Monad m) => m (a –> b) –> m a –> m b
>ap mf m = do
> f <– mf
> x <– m
> return (fx)
Функция >ap
– монадическое значение, результат которого – функция. Поскольку функция, как и значение, находится в контексте, мы берём функцию из контекста и называем её >f
, затем берём значение и называем его >x
, и, в конце концов, применяем функцию к значению и представляем это в качестве результата. Вот быстрая демонстрация:
>ghci> Just (+3) <*> Just 4
>Just 7
>ghci> Just (+3) `ap` Just 4
>Just 7
>ghci> [(+1),(+2),(+3)] <*> [10,11]
>[11,12,12,13,13,14]
>ghci> [(+1),(+2),(+3)] `ap` [10,11]
>[11,12,12,13,13,14]
Теперь нам видно, что монады настолько же сильны, насколько и аппликативные функторы, потому что мы можем использовать методы класса >Monad
для реализации функций из класса >Applicative
. На самом деле, когда обнаруживается, что определённый тип является монадой, зачастую сначала записывают экземпляр класса >Monad
, а затем создают экземпляр класса >Applicative
, просто говоря, что функция >pure
– это >return
, а операция ><*>
– это >ap
. Аналогичным образом, если у вас уже есть экземпляр класса >Monad
для чего-либо, вы можете сделать для него экземпляр класса >Functor
, просто говоря, что функция >fmap
– это >liftM
.
Функция >liftA2
весьма удобна для применения функции между двумя аппликативными значениями. Она определена вот так:
>liftA2 :: (Applicative f) => (a –> b –> c) –> f a –> f b –> f c
>liftA2 f x y = f <$> x <*> y
Функция >liftM2
делает то же, но с использованием ограничения >Monad
. Есть также функции >liftM3
, >liftM4
и >liftM5
.
Вы увидели, что монады не менее сильны, чем функторы и аппликативные функторы – и, хотя все монады, по сути, являются функторами и аппликативными функторами, у них необязательно имеются экземпляры классов >Functor
и >Applicative
. Мы изучили монадические эквиваленты функций, которые используются функторами и аппликативными функторами.
Есть кое-какая пища для размышления: если результат монадического значения – ещё одно монадическое значение (одно монадическое значение вложено в другое), можете ли вы «разгладить» их до одного лишь обычного монадического значения? Например, если у нас есть >Just (Just 9)
, можем ли мы превратить это в >Just 9
? Оказывается, что любое вложенное монадическое значение может быть разглажено, причём на самом деле это свойство уникально для монад. Для этого у нас есть функция >join
. Её тип таков:
>join :: (Monad m) => m (m a) –> m a
Значит, функция >join