Изучай Haskell во имя добра! (Липовача) - страница 266

. Функция >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. Мы изучили монадические эквиваленты функций, которые используются функторами и аппликативными функторами.

Функция join

Есть кое-какая пища для размышления: если результат монадического значения – ещё одно монадическое значение (одно монадическое значение вложено в другое), можете ли вы «разгладить» их до одного лишь обычного монадического значения? Например, если у нас есть >Just (Just 9), можем ли мы превратить это в >Just 9? Оказывается, что любое вложенное монадическое значение может быть разглажено, причём на самом деле это свойство уникально для монад. Для этого у нас есть функция >join. Её тип таков:

>join :: (Monad m) => m (m a) –> m a

Значит, функция >join