Eu vi o termo gratuito Mônada pop up a cada agora e , em seguida, por algum tempo, mas todo mundo só parece usar / discuti-los sem dar uma explicação sobre o que são. Então: o que são mônadas gratuitas? (Eu diria que estou familiarizado com as mônadas e os conceitos básicos de Haskell, mas tenho apenas um conhecimento muito rudimentar da teoria das categorias.)
haskell
monads
free-monad
David
fonte
fonte
Respostas:
A resposta de Edward Kmett é obviamente ótima. Mas, é um pouco técnico. Aqui está uma explicação talvez mais acessível.
Mônadas livres são apenas uma maneira geral de transformar functores em mônadas. Ou seja, dado que qualquer functor
f
Free f
é uma mônada. Isso não seria muito útil, exceto se você obtiver um par de funçõeso primeiro deles permite que você "entre" em sua mônada, e o segundo fornece uma maneira de "sair" dela.
De maneira mais geral, se X é um Y com algumas coisas extras P, então um "X livre" é uma maneira de passar de um Y para um X sem ganhar nada extra.
Exemplos: um monóide (X) é um conjunto (Y) com estrutura extra (P) que basicamente diz que possui uma operação (você pode pensar em adição) e alguma identidade (como zero).
assim
Agora, todos nós sabemos listas
Bem, dado qualquer tipo
t
, sabemos que[t]
é um monóidee assim as listas são o "monóide livre" sobre os conjuntos (ou nos tipos Haskell).
Ok, então mônadas gratuitas são a mesma ideia. Pegamos um functor e devolvemos uma mônada. De fato, como as mônadas podem ser vistas como monóides na categoria de endofunitores, a definição de uma lista
parece muito com a definição de mônadas livres
e a
Monad
instância tem uma semelhança com aMonoid
instância para listasagora, temos nossas duas operações
fonte
Free f a = Pure a | Roll (f (Free f a))
comoFree f a = a + fa + ffa + ...
, ou seja, "f aplicado a inúmeras vezes". EntãoconcatFree
(iejoin
) pega um "f aplicado qualquer número de vezes em (f aplicado qualquer número de vezes em a)" e recolhe os dois aplicativos aninhados em um. E>>=
pega "f aplicado inúmeras vezes a a" e "como passar de a a (b com f aplicado qualquer número de vezes)" e basicamente aplica o último a a dentro do primeiro e fecha o aninhamento. Agora eu mesmo entendo!concatFree
basicamentejoin
?Aqui está uma resposta ainda mais simples: Uma Mônada é algo que "calcula" quando o contexto monádico é recolhido
join :: m (m a) -> m a
(lembrando que>>=
pode ser definido comox >>= y = join (fmap y x)
). É assim que as Mônadas carregam o contexto através de uma cadeia seqüencial de cálculos: porque em cada ponto da série, o contexto da chamada anterior é recolhido com o próximo.Uma mônada livre satisfaz todas as leis da Mônada, mas não entra em colapso (isto é, computação). Ele apenas cria uma série aninhada de contextos. O usuário que cria um valor monádico gratuito é responsável por fazer algo com esses contextos aninhados, para que o significado de uma composição possa ser adiado até depois que o valor monádico for criado.
fonte
Um foo livre passa a ser a coisa mais simples que satisfaz todas as leis 'foo'. Isto é, satisfaz exatamente as leis necessárias para ser um foo e nada extra.
Um functor esquecido é aquele que "esquece" parte da estrutura à medida que passa de uma categoria para outra.
Dado functors
F : D -> C
, eG : C -> D
, dizemosF -| G
,F
é deixado adjacente aG
, ouG
é adjacente a todo momento emF
que todos a, b:F a -> b
é isomórfico paraa -> G b
, onde as setas vêm das categorias apropriadas.Formalmente, um functor livre fica adjacente a um functor esquecido.
O Monóide Livre
Vamos começar com um exemplo mais simples, o monóide livre.
Dê uma monoid, que é definida por um conjunto transportador
T
, uma função binário para esmagar um par de elementos juntosf :: T → T → T
, e umaunit :: T
, de modo que você tem uma lei associativa, e uma lei de identidade:f(unit,x) = x = f(x,unit)
.Você pode fazer um functor
U
da categoria de monoids (onde flechas são homomorphisms monoid, isto é, garantir que eles mapearunit
aunit
do outro monoid, e que você pode compor antes ou após o mapeamento para o outro monoid sem alterar o significado) à categoria de conjuntos (onde as setas são apenas setas funcionais) que 'esquecem' da operação eunit
, e apenas fornecem o conjunto da transportadora.Em seguida, você pode definir um functor
F
da categoria de conjuntos para a categoria de monoides que fica adjacente a esse functor. Esse functor é o functor que mapeia um conjuntoa
para o monóide[a]
, ondeunit = []
, emappend = (++)
.Então, para revisar nosso exemplo até agora, em pseudo-Haskell:
Então, para mostrar
F
é gratuito, precisamos demonstrar que ele fica adjacente aU
um functor esquecido, ou seja, como mencionamos acima, precisamos mostrar queF a → b
é isomórfico paraa → U b
Agora, lembre-se de que o alvo de
F
está na categoriaMon
de monóides, onde as setas são homomorfismos monóides; portanto, precisamos mostrar que um homomorfismo monóide de[a] → b
pode ser descrito precisamente por uma função dea → b
.Em Haskell, chamamos o lado disso que vive em
Set
(er,Hask
a categoria de tipos de Haskell que pretendemos ser Set), justfoldMap
, que quando especializada deData.Foldable
para Lists tem tipoMonoid m => (a → m) → [a] → m
.Há conseqüências que se seguem, sendo uma adjunção. Notavelmente, se você esquecer, construa gratuitamente, e esqueça novamente, é como você esqueceu uma vez, e podemos usar isso para criar a junção monádica. desde
UFUF
~U(FUF)
~UF
, e podemos passar o homomorfismo monóide de identidade de[a]
para[a]
o isomorfismo que define nossa adjunção, entender que um isomorfismo de lista[a] → [a]
é uma função do tipoa -> [a]
, e isso é apenas um retorno para listas.Você pode compor tudo isso mais diretamente, descrevendo uma lista nestes termos com:
The Free Monad
Então, o que é uma Mônada Livre ?
Bem, fazemos o mesmo que fizemos antes, começamos com um esquecido functor U da categoria de mônadas, onde as flechas são mônadas homomorfismos, até uma categoria de endofuncionadores, onde as flechas são transformações naturais, e procuramos um functor que fica ao lado para isso.
Então, como isso se relaciona com a noção de mônada livre, como costuma ser usada?
Saber que algo é uma mônada livre
Free f
, diz a você que fornecer uma homônima de mônadaFree f -> m
é a mesma coisa (isomórfica a) que fornecer uma transformação natural (de um homomorfismo de functor)f -> m
. Lembre-se de queF a -> b
deve ser isomórfico paraa -> U b
que F seja deixado adjacente a U. U aqui mapeou mônadas para functores.F é pelo menos isomorfo ao
Free
tipo que eu uso no meufree
pacote sobre hackage.Também podemos construí-lo em analogia mais rigorosa ao código acima para a lista livre, definindo
Comonadas Cofree
Podemos construir algo semelhante, observando o anexo correto de um functor esquecido, assumindo que ele existe. Um functor co-livre é simplesmente / diretamente adjunto / a um functor esquecido e, por simetria, saber que algo é uma comonada livre é o mesmo que saber que dar homomorfismo a uma comonada
w -> Cofree f
é o mesmo que dar uma transformação naturalw -> f
.fonte
A Mônada Livre (estrutura de dados) é para a Mônada (classe) como a Lista (estrutura de dados) para a Monóide (classe): é a implementação trivial, onde você pode decidir depois como o conteúdo será combinado.
Você provavelmente sabe o que é uma Mônada e que cada Mônada precisa de uma implementação específica (cumprindo a lei) de
fmap
+join
+return
oubind
+return
.Vamos supor que você tenha um Functor (uma implementação de
fmap
), mas o restante depende dos valores e escolhas feitos no tempo de execução, o que significa que você deseja poder usar as propriedades da Mônada, mas depois escolher as funções da Mônada.Isso pode ser feito usando a Mônada Livre (estrutura de dados), que agrupa o Functor (tipo) de tal maneira que
join
seja mais um empilhamento desses functores do que uma redução.O real
return
ejoin
você deseja usar agora podem ser dados como parâmetros para a função de reduçãofoldFree
:Para explicar os tipos, podemos substituir
Functor f
porMonad m
eb
por(m a)
:fonte
Uma mônada livre de Haskell é uma lista de functores. Comparar:
Pure
é análogoNil
eFree
é análogo aCons
. Uma mônada livre armazena uma lista de functores em vez de uma lista de valores. Tecnicamente, você pode implementar mônadas gratuitas usando um tipo de dados diferente, mas qualquer implementação deve ser isomórfica à mencionada acima.Você usa mônadas gratuitas sempre que precisar de uma árvore de sintaxe abstrata. O functor base da mônada livre é o formato de cada etapa da árvore de sintaxe.
Meu post , que alguém já vinculou, fornece vários exemplos de como criar árvores de sintaxe abstrata com mônadas gratuitas
fonte
Eu acho que um exemplo concreto simples ajudará. Suponha que tenhamos um functor
com o óbvio
fmap
. EntãoFree F a
é o tipo de árvores cujas folhas têm tipoa
e cujos nós são marcados comOne
,Two
,Two'
eThree
.One
-nodes têm um filho,Two
- eTwo'
-nodes têm dois filhos eThree
-nodes têm três e também são marcados com umInt
.Free F
é uma mônada.return
mapeiax
para a árvore que é apenas uma folha com valorx
.t >>= f
olha para cada uma das folhas e as substitui por árvores. Quando a folha tem valor,y
ela substitui a folha pela árvoref y
.Um diagrama torna isso mais claro, mas eu não tenho as facilidades para desenhar facilmente um!
fonte