. Функция
>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