Различие между классами типов MonadPlus, Alternative и Monoid?

Стандартные библиотеки классов типов Haskell MonadPlus, Alternative, а также Monoid каждый из них предоставляет два метода с практически одинаковой семантикой:

  • Пустое значение: mzero, empty, или же mempty,
  • Оператор a -> a -> a который объединяет значения в классе типов: mplus, <|>, или же mappend,

Все три определяют эти законы, которым должны придерживаться экземпляры:

mempty `mappend` x = x
x `mappend` mempty = x

Таким образом, кажется, что все три класса типов предоставляют одинаковые методы.

(Alternative также обеспечивает some а также many, но их определения по умолчанию обычно достаточно, и поэтому они не слишком важны с точки зрения этого вопроса.)

Итак, мой вопрос: почему у этих трех чрезвычайно похожих классов? Есть ли какая-то реальная разница между ними, помимо их ограничений суперкласса?

1 ответ

Решение

MonadPlus а также Monoid служить разным целям.

Monoid параметризован по типу вида *,

class Monoid m where
    mempty :: m
    mappend :: m -> m -> m

и поэтому он может быть создан практически для любого типа, для которого существует очевидный оператор, который является ассоциативным и который имеет единицу.

Тем не мение, MonadPlus не только указывает, что у вас есть моноидальная структура, но и что эта структура связана с тем, как Monad работает, и что эта структура не заботится о значении, содержащемся в монаде, на это (частично) указывает тот факт, что MonadPlus принимает аргумент типа * -> *,

class Monad m => MonadPlus m where
    mzero :: m a
    mplus :: m a -> m a -> m a

В дополнение к моноидным законам у нас есть два возможных набора законов, к которым мы можем применить MonadPlus, К сожалению, сообщество не согласно с тем, что они должны быть.

По крайней мере, мы знаем

mzero >>= k = mzero

но есть два других конкурирующих расширения, левый (sic) закон распределения

mplus a b >>= k = mplus (a >>= k) (b >>= k)

и левый улов закон

mplus (return a) b = return a

Так что любой случай MonadPlus должен удовлетворять одному или обоим из этих дополнительных законов.

Так что насчет Alternative ?

Applicative был определен после Monad и логически принадлежит как суперкласс Monad, но в значительной степени из-за разного давления на дизайнеров еще в Haskell 98, даже Functor не был суперклассом Monad до 2015 года. Теперь у нас наконец есть Applicative как суперкласс Monad в GHC (если еще не в стандарте языка.)

Эффективно, Alternative это к Applicative какие MonadPlus это к Monad,

За это мы бы получили

empty <*> m = empty

аналогично тому, что мы имеем с MonadPlus и существуют аналогичные свойства распределения и перехвата, по крайней мере одно из которых вы должны удовлетворить.

К сожалению даже empty <*> m = empty закон является слишком сильным требованием. Например, это не относится к Backwards!

Когда мы смотрим на MonadPlus, закон о пустом >>= f = empty почти навязывается нам. Пустая конструкция не может содержать никаких "а" для вызова функции f с в любом случае.

Тем не менее, так как Applicative не суперкласс Monad а также Alternative не суперкласс MonadPlus мы определяем оба экземпляра отдельно.

Более того, даже если Applicative был суперклассом Monad Вы бы нуждались в MonadPlus класс в любом случае, потому что даже если бы мы повиновались

empty <*> m = empty

этого недостаточно, чтобы доказать это

empty >>= f = empty

Так утверждая, что что-то MonadPlus сильнее, чем утверждать, что это Alternative,

Теперь, по соглашению, MonadPlus а также Alternative для данного типа следует согласиться, но Monoid может быть совершенно другим.

Например, MonadPlus а также Alternative за Maybe сделать очевидную вещь:

instance MonadPlus Maybe where
    mzero = Nothing
    mplus (Just a) _  = Just a
    mplus _        mb = mb

но Monoid Экземпляр поднимает полугруппу в Monoid, К сожалению, потому что не было Semigroup класс в то время в Haskell 98, он делает это, требуя Monoid, но не используя свой блок. ಠ_ಠ

instance Monoid a => Monoid (Maybe a) where
    mempty = Nothing
    mappend (Just a) (Just b) = Just (mappend a b)
    mappend Nothing x = x
    mappend x Nothing = x
    mappend Nothing Nothing = Nothing

TL; DR MonadPlus это более сильное требование, чем Alternative что, в свою очередь, является более сильным требованием, чем Monoid и пока MonadPlus а также Alternative экземпляры для типа должны быть связаны, Monoid может быть (а иногда и есть) что-то совершенно другое.

Другие вопросы по тегам