haskell - ¿Por qué MonadPlus y no Monad+Monoid?
monads monoids (2)
Estoy tratando de entender la motivación detrás de MonadPlus
. ¿Por qué es necesario si ya existen las clases de tipos Monad y Monoid
?
De acuerdo, las instancias de Monoid
son tipos concretos, mientras que las instancias de Monad
requieren un solo parámetro de tipo. (Consulte Monoid vs MonadPlus para obtener una explicación útil). ¿Pero no podría reescribir cualquier restricción de tipo de
(MonadPlus m) => ...
como una combinación de Monad
y Monoid
?
(Monad m, Monoid (m a)) => ...
Tome la función de guard
de Control.Monad
, por ejemplo. Su implementación es:
guard :: (MonadPlus m) => Bool -> m ()
guard True = return ()
guard False = mzero
Pude implementarlo usando solo Monad
y Monoid
:
guard'' :: (Monad m, Monoid (m ())) => Bool -> m ()
guard'' True = return ()
guard'' False = mempty
¿Podría alguien aclarar la diferencia real entre MonadPlus
y MonadPlus
+ Monoid
?
¿Pero no podrías reescribir cualquier restricción de tipo de
(MonadPlus m) => ...
como una combinación de Monad y Monoid?
No. En la respuesta superior a la pregunta que enlaza, ya hay una buena explicación sobre las leyes de MonadPlus vs. Monoid. Pero existen diferencias incluso si ignoramos las leyes de clases de tipos.
Monoid (ma) => ...
significa que ma
debe ser un monoide para un particular elegido por el que llama, pero MonadPlus m
significa que ma
debe ser un monoide para todo a
. Entonces, MonadPlus a
es más flexible y esta flexibilidad es útil en cuatro situaciones:
Si no queremos decirle a la persona que llama qué intentamos usar.
MonadPlus m => ...
lugar deMonoid (m SecretType) => ...
Si queremos usar múltiples diferentes
a
.
MonadPlus m => ...
lugar de(Monoid (m Type1), Monoid (m Type2), ...) => ...
Si queremos usar infinitamente muchos diferentes
a
.
MonadPlus m => ...
lugar de no es posible.Si no sabemos lo que necesitamos.
MonadPlus m => ...
lugar de no es posible.
Tu guard''
no coincide con tu tipo de Monoid ma
.
Si te refieres a Monoid (ma)
, entonces necesitas definir qué es mempty
para m ()
. Una vez que haya hecho eso, habrá definido un MonadPlus
.
En otras palabras, MonadPlus
define dos mzero
: mzero
y mplus
cumplen dos reglas: mzero
es neutral con respecto a mplus
, y mplus
es asociativo. Esto satisface la definición de mzero
para que mzero
sea mempty
y mplus
sea mappend
.
La diferencia es que MonadPlus m
es un MonadPlus m
ma
para cualquier a
, pero Monoid m
define un monoide solo para m
. Tu guard''
funciona porque solo necesitas que m
sea un Monoid
solo para ()
. Pero MonadPlus
es más fuerte, afirma que ma
es un monoide para cualquier a
.