haskell - semigrupo - Distinción entre las clases de tipos MonadPlus, Alternativa y Monoide?
semigrupo matematica discreta (1)
MonadPlus
y MonadPlus
tienen diferentes propósitos.
Un Monoid
se parametriza sobre un tipo de clase *
.
class Monoid m where
mempty :: m
mappend :: m -> m -> m
y entonces puede ser instanciado para casi cualquier tipo para el cual haya un operador obvio que sea asociativo y que tenga una unidad.
Sin embargo, MonadPlus
no solo especifica que tienes una estructura monoidal, sino también que esa estructura está relacionada con el funcionamiento de la Monad
, y que a esa estructura no le importa el valor contenido en la mónada, esto (en parte) se indica mediante el hecho de que MonadPlus
toma un argumento de tipo * -> *
.
class Monad m => MonadPlus m where
mzero :: m a
mplus :: m a -> m a -> m a
Además de las leyes de monoid, tenemos dos posibles conjuntos de leyes que podemos aplicar a MonadPlus
. Lamentablemente, la comunidad no está de acuerdo con lo que deberían ser.
Por lo menos, sabemos
mzero >>= k = mzero
pero hay otras dos extensiones en competencia, la ley de distribución de la izquierda (sic)
mplus a b >>= k = mplus (a >>= k) (b >>= k)
y la ley de captura a la izquierda
mplus (return a) b = return a
Entonces cualquier instancia de MonadPlus
debería satisfacer una o ambas de estas leyes adicionales.
Entonces, ¿qué pasa con Alternative
?
Applicative
fue definido después de Monad
, y lógicamente pertenece como una superclase de Monad
, pero en gran parte debido a las diferentes presiones sobre los diseñadores en Haskell 98, incluso Functor
no era una superclase de Monad
hasta 2015. Ahora finalmente tenemos Applicative
como una superclase de Monad
en GHC (si aún no está en un estándar de idioma)
Efectivamente, la Alternative
es Applicative
lo que MonadPlus
es para MonadPlus
.
Para estos, obtendríamos
empty <*> m = empty
de forma análoga a lo que tenemos con MonadPlus
y existen propiedades distributivas y de captura similares, al menos una de las cuales debe satisfacer.
Desafortunadamente, incluso la empty <*> m = empty
ley empty <*> m = empty
es un reclamo demasiado fuerte. ¡No sirve para Backwards , por ejemplo!
Cuando miramos a MonadPlus, la ley vacía >> = f = empty casi nos es forzada. La construcción vacía no puede tener ninguna ''a'' para llamar a la función f
de todos modos.
Sin embargo, dado que Applicative
no es una superclase de Monad
y Alternative
no es una superclase de MonadPlus
, terminaremos definiendo ambas instancias por separado.
Además, incluso si Applicative
fuera una superclase de Monad
, terminarías necesitando la clase MonadPlus
todos modos, porque incluso si MonadPlus
empty <*> m = empty
eso no es estrictamente suficiente para demostrar que
empty >>= f = empty
Entonces, afirmar que algo es un MonadPlus
es más fuerte que afirmar que es Alternative
.
Ahora, por convención, el MonadPlus
y la Alternative
para un tipo dado deberían estar de acuerdo, pero el Monoid
puede ser completamente diferente.
Por ejemplo, MonadPlus
y Alternative
for Maybe
hacen lo obvio:
instance MonadPlus Maybe where
mzero = Nothing
mplus (Just a) _ = Just a
mplus _ mb = mb
pero la instancia de Monoid
levanta un semigroup en un Monoid
. Tristemente porque no existía una clase Semigroup
en ese momento en Haskell 98, lo hace al requerir un Monoid, pero sin usar su unidad. ಠ_ಠ
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
es una afirmación más sólida que Alternative
, que a su vez es una afirmación más sólida que Monoid
, y si bien las instancias MonadPlus
y Alternative
para un tipo deberían estar relacionadas, el Monoid
puede ser (y algunas veces es) algo completamente diferente.
Las clases de MonadPlus
Haskell de biblioteca estándar MonadPlus
, Alternative
y Monoid
proporcionan dos métodos con esencialmente la misma semántica:
- Un valor vacío:
mzero
,empty
omempty
. - Un operador
a -> a -> a
que une los valores en la clase de tipos juntos:mplus
,<|>
omappend
.
Los tres especifican estas leyes a las cuales deben adherirse las instancias:
mempty `mappend` x = x
x `mappend` mempty = x
Por lo tanto, parece que las tres clases de tipos proporcionan los mismos métodos.
(La Alternative
también proporciona some
y many
, pero sus definiciones predeterminadas suelen ser suficientes, por lo que no son demasiado importantes en términos de esta pregunta).
Entonces, mi pregunta es: ¿por qué estas tres clases extremadamente similares? ¿Hay alguna diferencia real entre ellos, además de sus diferentes restricciones de superclase?