Los candidatos componen, las mónadas no.
¿Qué significa la declaración anterior? ¿Y cuándo es preferible uno a otro?
haskell
functional-programming
monads
monad-transformers
applicative
desaparecido faktor
fuente
fuente
Applicative
s son en realidad una familia completa deMonad
s, es decir, uno para cada "forma" de estructura posible.ZipList
no es aMonad
, peroZipList
s de longitud fija son.Reader
es un caso especial conveniente (¿o es general?) donde el tamaño de la "estructura" se fija como la cardinalidad del tipo de entorno.Reader
mónada hasta un isomorfismo. Una vez que fija la forma de un contenedor, codifica efectivamente una función a partir de posiciones, como un memo trie. Peter Hancock llama a estos functores "naperianos", ya que obedecen las leyes de los logaritmos.Respuestas:
Si comparamos los tipos
tenemos una pista de lo que separa los dos conceptos. Que
(s -> m t)
en el tipo de(>>=)
muestra que un valor ens
puede determinar el comportamiento de un cálculo enm t
. Las mónadas permiten la interferencia entre las capas de valor y de cálculo. El(<*>)
operador no permite tal interferencia: los cálculos de la función y el argumento no dependen de los valores. Esto realmente muerde. Compararque utiliza el resultado de algún efecto para decidir entre dos cálculos (por ejemplo, lanzar misiles y firmar un armisticio), mientras que
que utiliza el valor de
ab
para elegir entre los valores de dos cálculosat
yaf
, habiendo realizado ambos, quizás con efecto trágico.La versión monádica se basa esencialmente en el poder adicional de
(>>=)
elegir un cálculo a partir de un valor, y eso puede ser importante. Sin embargo, apoyar ese poder hace que las mónadas sean difíciles de componer. Si intentamos construir 'doble vínculo'llegamos hasta aquí, pero ahora nuestras capas están revueltas. Tenemos un
n (m (n t))
, así que tenemos que deshacernos del exteriorn
. Como dice Alexandre C, podemos hacer eso si tenemos unpermutar el
n
interior yjoin
el otron
.La 'doble aplicación' más débil es mucho más fácil de definir
porque no hay interferencia entre las capas.
En consecuencia, es bueno reconocer cuándo realmente necesita la potencia adicional de
Monad
s, y cuándo puede salirse con la suya con la rígida estructura de cálculo queApplicative
admite.Tenga en cuenta, por cierto, que aunque componer mónadas es difícil, puede ser más de lo que necesita. El tipo
m (n v)
indica computación conm
-effects, luego computación conn
-effects a unv
-valor, donde losm
-effects terminan antes de quen
comiencen los -effects (de ahí la necesidad deswap
). Si solo desea intercalarm
-efectos conn
-efectos, entonces la composición es quizás demasiado pedir.fuente
m
yn
siempre se puede escribir un transformador mónadamt
, y operar enn (m t)
el usomt n t
? Entonces, ¿siempre puedes componer mónadas, es más complicado, usar transformadores?data Free f x = Ret x | Do (f (Free f x))
, entoncesdata (:+:) f g x = Inl (f x) | Tnr (g x)
, y considereFree (m :+: n)
. Eso retrasa la elección de cómo ejecutar intercalados.Maybe
esto significa que un tempranoNothing
suprimirá la evaluacióna
de un posterior / posteriorJust a
. ¿Es esto correcto?Mónadas hacen componer, pero el resultado podría no ser una mónada. Por el contrario, la composición de dos aplicativos es necesariamente un aplicativo. Sospecho que la intención de la declaración original era que "la aplicabilidad compone, mientras que la mónada no". Reformulado, "
Applicative
está cerrado bajo composición yMonad
no lo es".fuente
Si tiene aplicativos
A1
yA2
, entonces el tipodata A3 a = A3 (A1 (A2 a))
también es aplicativo (puede escribir tal instancia de forma genérica).Por otro lado, si usted tiene mónadas
M1
yM2
entonces el tipodata M3 a = M3 (M1 (M2 a))
no es necesariamente una mónada (no hay una implementación genérica sensato>>=
ojoin
de la composición).Un ejemplo puede ser el tipo
[Int -> a]
(aquí componimos un constructor de tipos[]
con(->) Int
, los cuales son mónadas). Puedes escribir fácilmenteY eso se generaliza a cualquier aplicativo:
Pero no existe una definición sensata de
Si no está convencido de esto, considere esta expresión:
La longitud de la lista devuelta se debe establecer en piedra antes de que se proporcione un número entero, pero la longitud correcta depende del número entero que se proporcione. Por tanto, no
join
puede existir una función correcta para este tipo.fuente
IO
sin unMonad
sería muy difícil de programar. :)Composición de mónadas, http://web.cecs.pdx.edu/~mpj/pubs/RR-1004.pdf
fuente
swap : N M a -> M N a
ContT r m a
no es nim (Cont r a)
tampocoCont r (m a)
, yStateT s m a
es más o menosReader s (m (Writer s a))
.swap
implica que la composición permite a los dos "cooperar" de alguna manera. Además, tenga en cuenta quesequence
es un caso especial de "intercambio" para algunas mónadas. Enflip
realidad, también lo es.swap :: N (M x) -> M (N x)
, me parece que puede usarreturns
(adecuadamentefmap
ped) para insertar unM
en el frente y unN
en la parte posterior, yendo desdeN (M x) -> M (N (M (N x)))
, luego use eljoin
del compuesto para obtener suM (N x)
.La solución de la ley distributiva l: MN -> NM es suficiente
para garantizar la monadicidad de NM. Para ver esto necesitas una unidad y un mult. Me enfocaré en el mult (la unidad es unit_N unitM)
Esto no garantiza que MN sea una mónada.
Sin embargo, la observación crucial entra en juego cuando tiene soluciones de ley distributiva
por tanto, LM, LN y MN son mónadas. Surge la pregunta de si LMN es una mónada (ya sea por
(MN) L -> L (MN) o por N (LM) -> (LM) N
Tenemos suficiente estructura para hacer estos mapas. Sin embargo, como observa Eugenia Cheng , necesitamos una condición hexagonal (que equivale a una presentación de la ecuación de Yang-Baxter) para garantizar la monadicidad de cualquier construcción. De hecho, con la condición hexagonal, las dos mónadas diferentes coinciden.
fuente