Сначала я бы назвал это шаблоном в том смысле, что ma -> (a -> mb) -> mb (с разумным поведением) удобен для множества различных задач / конструкторов типов.
На самом деленастолько удобный, что он заслуживает предоставления некоторого синтаксического сахара в языке.Это нотация do
в Haskell, from
в C #, for
понимания в scala.При реализации синтетического сахара требуется только соблюдение шаблона именования (selectMany
в C #, flatMap
в scala).Эти языки делают это без Монады, являющейся типом в их библиотеках (в scala можно написать один).Обратите внимание, что C # делает это и для шаблона Iterator.В то время как есть интерфейс IEnumerable, foreach
переводится в вызовы к GetEnumerator
/ MoveNext
/ Current
на основании имени методов, независимо от типов.Только когда перевод выполнен, он проверяет, что все определено и правильно напечатано.
Но в Haskell (это может быть сделано также в Scala или OCaml, не в C #, и я считаю, что это невозможно и в F #).), Monad - это больше, чем шаблон дизайна + синтетический сахар на основе шаблона именования.Это фактический API, программный компонент, что угодно.
Рассмотрим шаблон итератора в (статически типизированных) императивных языках.Вы можете просто реализовать MoveNext
/ Current
(или hasNext
/ next
) в классах, где это уместно.И если для этого есть какой-то синтаксический сахар, такой как C #, это уже весьма полезно.Но если вы сделаете это интерфейсом, вы сразу сможете сделать гораздо больше.Вы можете иметь вычисления, которые работают на любом итераторе.У вас могут быть служебные методы на итераторе (find, filter, chain, nest ..), делающие их более мощными.
Когда Monad является типом, а не просто шаблоном, вы можете сделать то же самое.У вас могут быть служебные функции, которые делают работу с Monad более мощной (в Control.Monad ) вы можете выполнять вычисления, где тип используемой монады является параметром (см. Эту старую статью изВадлер, показывающий, как интерпретировать интерпретатор по типу монады и что делают различные экземпляры).Чтобы иметь тип монады (класс типов), вам нужен какой-то тип более высокого порядка, то есть вы должны иметь возможность параметризации с помощью конструктора типов, а не простого типа данных.