He visto el término libre mónada pop-up cada ahora y entonces durante algún tiempo, pero todo el mundo parece utilizar / discutirlas sin dar una explicación de lo que son. Entonces: ¿qué son las mónadas libres? (Diría que estoy familiarizado con las mónadas y los conceptos básicos de Haskell, pero solo tengo un conocimiento muy aproximado de la teoría de categorías).
haskell
monads
free-monad
David
fuente
fuente
Respuestas:
La respuesta de Edward Kmett es obviamente genial. Pero, es un poco técnico. Aquí hay una explicación quizás más accesible.
Las mónadas gratuitas son solo una forma general de convertir a los functores en mónadas. Es decir, dado que cualquier functor
f
Free f
es una mónada. Esto no sería muy útil, excepto que obtienes un par de funcionesel primero de estos le permite "entrar" en su mónada, y el segundo le da una forma de "salir" de él.
En términos más generales, si X es una Y con algunas cosas adicionales P, entonces una "X libre" es una forma de pasar de una Y a una X sin ganar nada extra.
Ejemplos: un monoide (X) es un conjunto (Y) con estructura adicional (P) que básicamente dice que tiene una operación (puede pensar en la suma) y cierta identidad (como cero).
Entonces
Ahora, todos sabemos listas
Bueno, dado cualquier tipo
t
, sabemos que[t]
es un monoidey entonces las listas son el "monoide libre" sobre conjuntos (o en tipos Haskell).
Bien, entonces las mónadas gratis son la misma idea. Tomamos un functor y devolvemos una mónada. De hecho, dado que las mónadas se pueden ver como monoides en la categoría de endofunctores, la definición de una lista
se parece mucho a la definición de mónadas libres
y la
Monad
instancia tiene una similitud con laMonoid
instancia para listasahora tenemos nuestras dos operaciones
fuente
Free f a = Pure a | Roll (f (Free f a))
comoFree f a = a + fa + ffa + ...
, es decir, "f aplicado a cualquier cantidad de veces". LuegoconcatFree
(es decirjoin
) toma una "f aplicada cualquier cantidad de veces a (f aplicada cualquier cantidad de veces a a)" y contrae las dos aplicaciones anidadas en una. Y>>=
toma "f aplicado cualquier número de veces a a" y "cómo llegar de a a (b con f aplicado cualquier número de veces)", y básicamente aplica el último a a dentro del primero y colapsa el anidamiento. ¡Ahora yo mismo lo entiendo!concatFree
básicamentejoin
?Aquí hay una respuesta aún más simple: una mónada es algo que "computa" cuando se colapsa el contexto monádico
join :: m (m a) -> m a
(recordando que>>=
se puede definir comox >>= y = join (fmap y x)
). Así es como las mónadas llevan el contexto a través de una cadena secuencial de cálculos: porque en cada punto de la serie, el contexto de la llamada anterior se contrae con la siguiente.Una mónada libre satisface todas las leyes de la mónada, pero no colapsa (es decir, el cálculo). Simplemente construye una serie anidada de contextos. El usuario que crea un valor monádico libre es responsable de hacer algo con esos contextos anidados, de modo que el significado de dicha composición pueda diferirse hasta después de que se haya creado el valor monádico.
fuente
Un foo libre resulta ser lo más simple que satisface todas las leyes de 'foo'. Es decir, satisface exactamente las leyes necesarias para ser un tonto y nada más.
Un functor olvidadizo es aquel que "olvida" parte de la estructura a medida que pasa de una categoría a otra.
Dados functores
F : D -> C
, yG : C -> D
, decimosF -| G
,F
se deja adjunto aG
, oG
es justo contiguo aF
cada vez que a, b:F a -> b
es isomorfo aa -> G b
, donde las flechas provienen de las categorías apropiadas.Formalmente, un functor gratuito se deja adjunto a un functor olvidadizo.
El monoide libre
Comencemos con un ejemplo más simple, el monoide gratuito.
Tome un monoide, que se define por un conjunto de soporte
T
, una función binaria para triturar un par de elementos juntosf :: T → T → T
, y unaunit :: T
, de manera que usted tiene una ley asociativa, y una ley de identidad:f(unit,x) = x = f(x,unit)
.Puede hacer un funtor
U
de la categoría de monoides (donde las flechas son homomorfismos monoides, es decir, que aseguran se asignanunit
aunit
por otro monoide, y que se pueden componer antes o después de la cartografía a la otra monoid sin cambiar el significado) a la categoría de conjuntos (donde las flechas son solo flechas de función) que 'se olvida' de la operaciónunit
y solo le da el conjunto de portadores.Luego, puede definir un functor
F
desde la categoría de conjuntos hasta la categoría de monoides que se adjunta a este functor. Ese functor es el functor que asigna un conjuntoa
al monoide[a]
, dondeunit = []
ymappend = (++)
.Entonces, para revisar nuestro ejemplo hasta ahora, en pseudo-Haskell:
Luego, para mostrar
F
es gratuito, tenemos que demostrar que se deja adjunto aU
un functor olvidadizo, es decir, como mencionamos anteriormente, tenemos que demostrar queF a → b
es isomorfo aa → U b
Ahora, recuerde que el objetivo de
F
está en la categoríaMon
de monoides, donde las flechas son homomorfismos monoides, por lo que necesitamos un para demostrar que un homomorfismo monoide[a] → b
puede describirse precisamente por una función dea → b
.En Haskell, llamamos al lado de esto que vive en
Set
(er,Hask
la categoría de tipos de Haskell que pretendemos es Set), simplementefoldMap
, que cuando se especializa desdeData.Foldable
a Listas tiene tipoMonoid m => (a → m) → [a] → m
.Hay consecuencias que se derivan de que esto sea un complemento. Notablemente, si olvidas, entonces construye con gratis, luego vuelve a olvidar, es como lo olvidaste una vez, y podemos usar esto para construir la unión monádica. desde
UFUF
~U(FUF)
~UF
, y podemos pasar el homomorfismo monoide de identidad de[a]
a[a]
través del isomorfismo que define nuestro adjunto, hacer que una lista de isomorfismo[a] → [a]
sea una función de tipoa -> [a]
, y esto es solo el retorno para las listas.Puede componer todo esto más directamente describiendo una lista en estos términos con:
La mónada libre
Entonces, ¿qué es una mónada libre ?
Bueno, hacemos lo mismo que hicimos antes, comenzamos con un functor olvidadizo U de la categoría de mónadas donde las flechas son homomorfismos de mónada a una categoría de endofunctores donde las flechas son transformaciones naturales, y buscamos un functor que quede adjunto a ese.
Entonces, ¿cómo se relaciona esto con la noción de una mónada libre como se usa generalmente?
Sabiendo que algo es una mónada libre,
Free f
te dice que dar un homomorfismo de mónadaFree f -> m
es lo mismo (isomorfo a) que dar una transformación natural (un homomorfismo functor)f -> m
. Recuerde queF a -> b
debe ser isomorfoa -> U b
para que F se quede junto a U. U aquí asigna mónadas a functors.F es al menos isomorfo al
Free
tipo que uso en mifree
paquete de piratería.También podríamos construirlo en una analogía más estricta con el código anterior para la lista gratuita, definiendo
Cofree Comonads
Podemos construir algo similar, mirando el adjunto correcto a un functor olvidadizo, suponiendo que exista. Un cofundador es simplemente / justo adjunto / a un olvidadizo, y por simetría, saber que algo es un cofre comonad es lo mismo que saber que dar un comonad homomorfismo
w -> Cofree f
es lo mismo que dar una transformación naturalw -> f
.fuente
La mónada libre (estructura de datos) es para la mónada (clase) como la lista (estructura de datos) para el monoide (clase): es la implementación trivial, donde luego puede decidir cómo se combinará el contenido.
Probablemente sepa qué es una mónada y que cada mónada necesita una implementación específica (respetando la ley de mónada) de
fmap
+join
+return
obind
+return
.Supongamos que tiene un Functor (una implementación de
fmap
), pero el resto depende de los valores y las elecciones realizadas en tiempo de ejecución, lo que significa que desea poder utilizar las propiedades de Monad pero luego desea elegir las funciones de Monad.Eso se puede hacer usando la Mónada Libre (estructura de datos), que envuelve el Functor (tipo) de tal manera que
join
es más bien un apilamiento de esos functores que una reducción.Lo real
return
y lojoin
que quiere usar ahora se puede dar como parámetros para la función de reducciónfoldFree
:Para explicar los tipos, podemos reemplazar
Functor f
conMonad m
yb
con(m a)
:fuente
Una mónada libre de Haskell es una lista de functors. Comparar:
Pure
es análogo aNil
yFree
es análogo aCons
. Una mónada gratuita almacena una lista de functores en lugar de una lista de valores. Técnicamente, podría implementar mónadas libres utilizando un tipo de datos diferente, pero cualquier implementación debería ser isomorfa a la anterior.Utiliza mónadas gratis siempre que necesites un árbol de sintaxis abstracta. El functor base de la mónada libre es la forma de cada paso del árbol de sintaxis.
Mi publicación , que alguien ya ha vinculado, ofrece varios ejemplos de cómo construir árboles de sintaxis abstracta con mónadas gratuitas
fuente
Creo que un simple ejemplo concreto ayudará. Supongamos que tenemos un functor
con lo obvio
fmap
. A continuación,Free F a
es el tipo de árboles cuyas hojas tienen el tipoa
y cuyos nodos están etiquetados conOne
,Two
,Two'
yThree
.One
-nodes tienen un hijo,Two
- yTwo'
-nodes tienen dos hijos yThree
-nodes tienen tres y también están etiquetados con unInt
.Free F
Es una mónada.return
asignax
al árbol que es solo una hoja con valorx
.t >>= f
mira cada una de las hojas y las reemplaza con árboles. Cuando la hoja tiene valory
, reemplaza esa hoja con el árbolf y
.¡Un diagrama lo aclara, pero no tengo las facilidades para dibujarlo fácilmente!
fuente