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

и >1 в стек, а затем выполняется выражение >push 10, проталкивая число >10 на верхушку.

Реализация для функции >join такова:

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

>join mm = do

>   m <– mm

>   m

Поскольку результат >mm является монадическим значением, мы берём этот результат, а затем просто помещаем его на его собственную строку, потому что это и есть монадическое значение. Трюк здесь в том, что когда мы вызываем выражение >m><–>mm, контекст монады, в которой мы находимся, будет обработан. Вот почему, например, значения типа >Maybe дают в результате значения >Just, только если и внешнее, и внутреннее значения являются значениями >Just. Вот как это выглядело бы, если бы значение >mm было заранее установлено в >Just (Just 8):

>joinedMaybes :: Maybe Int

>joinedMaybes = do

>   m <– Just (Just 8)

>   m

Наверное, самое интересное в функции >join – то, что для любой монады передача монадического значения в функцию с помощью операции >>>= представляет собой то же самое, что и просто отображение значения с помощью этой функции, а затем использование функции >join для разглаживания результирующего вложенного монадического значения! Другими словами, выражение >m >>= f – всегда то же самое, что и >join (fmap f m). Если вдуматься, это имеет смысл.

При использовании операции >>>= мы постоянно думаем, как передать монадическое значение функции, которая принимает обычное значение, а возвращает монадическое. Если мы просто отобразим монадическое значение с помощью этой функции, то получим монадическое значение внутри монадического значения. Например, скажем, у нас есть >Just 9 и функция >\x –> Just (x+1). Если с помощью этой функции мы отобразим >Just 9, у нас останется >Just (Just 10).

То, что выражение >m >>= f всегда равно >join (fmap f m), очень полезно, если мы создаём свой собственный экземпляр класса >Monad для некоего типа. Это связано с тем, что зачастую проще понять, как мы бы разгладили вложенное монадическое значение, чем понять, как реализовать операцию >>>=.



Ещё интересно то, что функция >join не может быть реализована, всего лишь используя функции, предоставляемые функторами и аппликативными функторами. Это приводит нас к заключению, что монады не просто сопоставимы по своей силе с функторами и аппликативными функторами – они на самом деле сильнее, потому что с ними мы можем делать больше, чем просто с функторами и аппликативными функторами.

Функция filterM

Функция >filter – это просто хлеб программирования на языке Haskell (при том что функция >map – масло). Она принимает предикат и список, подлежащий фильтрации, а затем возвращает новый список, в котором сохраняются только те элементы, которые удовлетворяют предикату. Её тип таков: