MonadPlus
e Monoid
servem a diferentes propósitos.
A Monoid
é parametrizado sobre um tipo de tipo *
.
class Monoid m where
mempty :: m
mappend :: m -> m -> m
e, portanto, pode ser instanciado para quase qualquer tipo para o qual haja um operador óbvio que seja associativo e que tenha uma unidade.
No entanto, MonadPlus
não especifica apenas que você tem uma estrutura monoidal, mas também que essa estrutura está relacionada a como Monad
funciona, e que essa estrutura não se preocupa com o valor contido na mônada, isso é (em parte) indicado pelo fato isso MonadPlus
leva um argumento do tipo * -> *
.
class Monad m => MonadPlus m where
mzero :: m a
mplus :: m a -> m a -> m a
Além das leis monoidais, temos dois conjuntos potenciais de leis que podemos aplicar MonadPlus
. Infelizmente, a comunidade discorda quanto ao que deveriam ser.
Pelo menos sabemos
mzero >>= k = mzero
mas há duas outras extensões concorrentes, a lei de distribuição de esquerda (sic)
mplus a b >>= k = mplus (a >>= k) (b >>= k)
e a esquerda pega a lei
mplus (return a) b = return a
Portanto, qualquer instância de MonadPlus
deve satisfazer uma ou ambas as leis adicionais.
Então sobre o quê Alternative
?
Applicative
foi definido depois Monad
, e logicamente pertence como uma superclasse de Monad
, mas em grande parte devido às diferentes pressões sobre os designers em Haskell 98, ainda Functor
não era uma superclasse de Monad
até 2015. Agora finalmente temos Applicative
como uma superclasse de Monad
em GHC (se não ainda em um padrão de idioma.)
Efetivamente, Alternative
é para o Applicative
que MonadPlus
é Monad
.
Para estes nós obteríamos
empty <*> m = empty
analogamente ao que temos com MonadPlus
e existem propriedades distributivas e de captura semelhantes, pelo menos uma das quais você deve satisfazer.
Infelizmente, mesmo a empty <*> m = empty
lei é uma afirmação muito forte. Não vale para Backwards , por exemplo!
Quando olhamos para MonadPlus, a lei vazia >> = f = vazia é quase imposta a nós. A construção vazia não pode ter nenhum 'a's nela para chamar a função de f
qualquer maneira.
No entanto, como nãoApplicative
é uma superclasse de e não é uma superclasse de , acabamos definindo ambas as instâncias separadamente.Monad
Alternative
MonadPlus
Além disso, mesmo se Applicative
fosse uma superclasse de Monad
, você acabaria precisando da MonadPlus
classe de qualquer maneira, porque mesmo se nós obedecêssemos
empty <*> m = empty
isso não é estritamente suficiente para provar que
empty >>= f = empty
Portanto, afirmar que algo é a MonadPlus
é mais forte do que afirmar que é Alternative
.
Agora, por convenção, o MonadPlus
e Alternative
para um determinado tipo devem concordar, mas o Monoid
pode ser completamente diferente.
Por exemplo, o MonadPlus
e Alternative
para Maybe
fazem a coisa óbvia:
instance MonadPlus Maybe where
mzero = Nothing
mplus (Just a) _ = Just a
mplus _ mb = mb
mas a Monoid
instância eleva um semigrupo em a Monoid
. Infelizmente, porque não existia uma Semigroup
classe na época em Haskell 98, ele faz isso solicitando a Monoid
, mas não usando sua unidade. ಠ_ಠ
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
é uma afirmação mais forte do que Alternative
, que por sua vez é uma afirmação mais forte do que Monoid
, e embora as instâncias MonadPlus
e Alternative
para um tipo devam estar relacionadas, Monoid
pode ser (e às vezes é) algo completamente diferente.
Applicative
eMonadPlus
parecem ser exatamente os mesmos (restrições da superclasse do módulo).