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
fFree fes 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
Monadinstancia tiene una similitud con laMonoidinstancia 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!concatFreebá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,Fse deja adjunto aG, oGes justo contiguo aFcada vez que a, b:F a -> bes 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
Ude la categoría de monoides (donde las flechas son homomorfismos monoides, es decir, que aseguran se asignanunitaunitpor 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ónunity solo le da el conjunto de portadores.Luego, puede definir un functor
Fdesde 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 conjuntoaal monoide[a], dondeunit = []ymappend = (++).Entonces, para revisar nuestro ejemplo hasta ahora, en pseudo-Haskell:
Luego, para mostrar
Fes gratuito, tenemos que demostrar que se deja adjunto aUun functor olvidadizo, es decir, como mencionamos anteriormente, tenemos que demostrar queF a → bes isomorfo aa → U bAhora, recuerde que el objetivo de
Festá en la categoríaMonde monoides, donde las flechas son homomorfismos monoides, por lo que necesitamos un para demostrar que un homomorfismo monoide[a] → bpuede describirse precisamente por una función dea → b.En Haskell, llamamos al lado de esto que vive en
Set(er,Haskla categoría de tipos de Haskell que pretendemos es Set), simplementefoldMap, que cuando se especializa desdeData.Foldablea 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 fte dice que dar un homomorfismo de mónadaFree f -> mes lo mismo (isomorfo a) que dar una transformación natural (un homomorfismo functor)f -> m. Recuerde queF a -> bdebe ser isomorfoa -> U bpara que F se quede junto a U. U aquí asigna mónadas a functors.F es al menos isomorfo al
Freetipo que uso en mifreepaquete 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 fes 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+returnobind+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
joines más bien un apilamiento de esos functores que una reducción.Lo real
returny lojoinque quiere usar ahora se puede dar como parámetros para la función de reducciónfoldFree:Para explicar los tipos, podemos reemplazar
Functor fconMonad mybcon(m a):fuente
Una mónada libre de Haskell es una lista de functors. Comparar:
Purees análogo aNilyFreees 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 aes el tipo de árboles cuyas hojas tienen el tipoay 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 FEs una mónada.returnasignaxal árbol que es solo una hoja con valorx.t >>= fmira 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