Je l' ai vu le terme gratuit Monad pop - up chaque maintenant et puis pendant un certain temps, mais tout le monde semble juste d'utiliser / en discuter sans donner une explication de ce qu'ils sont. Alors: que sont les monades gratuites? (Je dirais que je connais les monades et les bases de Haskell, mais que je n'ai qu'une connaissance très approximative de la théorie des catégories.)
haskell
monads
free-monad
David
la source
la source
Réponses:
La réponse d'Edward Kmett est évidemment excellente. Mais c'est un peu technique. Voici une explication peut-être plus accessible.
Les monades gratuites ne sont qu'un moyen général de transformer des foncteurs en monades. Autrement dit, étant donné que tout foncteur
f
Free f
est une monade. Ce ne serait pas très utile, sauf si vous obtenez une paire de fonctionsle premier vous permet de "rentrer" dans votre monade, et le second vous donne un moyen de "sortir" de celle-ci.
Plus généralement, si X est un Y avec quelques trucs supplémentaires P, alors un "X libre" est un moyen de passer d'un Y à un X sans rien gagner de plus.
Exemples: un monoïde (X) est un ensemble (Y) avec une structure supplémentaire (P) qui dit essentiellement qu'il a une opération (vous pouvez penser à l'addition) et une certaine identité (comme zéro).
Donc
Maintenant, nous connaissons tous des listes
Eh bien, étant donné tout type,
t
nous savons que[t]
c'est un monoïdeet ainsi les listes sont le "monoïde libre" sur les ensembles (ou dans les types Haskell).
D'accord, donc les monades gratuites sont la même idée. Nous prenons un foncteur et rendons une monade. En fait, comme les monades peuvent être considérées comme des monoïdes dans la catégorie des endofoncteurs, la définition d'une liste
ressemble beaucoup à la définition des monades libres
et l'
Monad
instance a une similitude avec l'Monoid
instance pour les listesmaintenant, nous obtenons nos deux opérations
la source
Free f a = Pure a | Roll (f (Free f a))
commeFree f a = a + fa + ffa + ...
, c'est-à-dire "f appliqué à un certain nombre de fois". EnsuiteconcatFree
(c'est-à-direjoin
) prend un "f appliqué un nombre illimité de fois à (f appliqué un nombre illimité de fois à un)" et réduit les deux applications imbriquées en une seule. Et>>=
prend "f appliqué un certain nombre de fois à un" et "comment aller de a à (b avec f appliqué un certain nombre de fois)", et applique fondamentalement ce dernier aux a à l'intérieur du premier et effondre l'imbrication. Maintenant, je comprends moi-même!concatFree
fondamentalementjoin
?Voici une réponse encore plus simple: Une Monade est quelque chose qui "calcule" lorsque le contexte monadique est réduit par
join :: m (m a) -> m a
(rappelant que cela>>=
peut être défini commex >>= y = join (fmap y x)
). C'est ainsi que les Monades transportent le contexte à travers une chaîne séquentielle de calculs: car à chaque point de la série, le contexte de l'appel précédent est réduit au suivant.Une monade libre satisfait à toutes les lois de la monade, mais ne fait pas d'effondrement (c.-à-d. Calcul). Il crée simplement une série de contextes imbriqués. L'utilisateur qui crée une telle valeur monadique libre est responsable de faire quelque chose avec ces contextes imbriqués, de sorte que la signification d'une telle composition puisse être différée jusqu'à ce que la valeur monadique ait été créée.
la source
Un foo gratuit se trouve être la chose la plus simple qui satisfait toutes les lois du foo. C'est-à-dire qu'il satisfait exactement aux lois nécessaires pour être un fou et rien de plus.
Un foncteur oublieux est celui qui «oublie» une partie de la structure en passant d'une catégorie à l'autre.
Des foncteurs donnés
F : D -> C
, etG : C -> D
, disons-nousF -| G
,F
sont adjoints à gaucheG
ouG
sont adjoints à droiteF
chaque fois que tout a, b:F a -> b
est isomorphe àa -> G b
, où les flèches proviennent des catégories appropriées.Formellement, un foncteur libre est laissé adjoint à un foncteur oublieux.
Le monoïde gratuit
Commençons par un exemple plus simple, le monoïde libre.
Prenez un monoïde, qui est défini par un ensemble de support
T
, une fonction binaire pour écraser une paire d'éléments ensemblef :: T → T → T
, etunit :: T
, de sorte que vous avez une loi associative, et une loi d'identité:f(unit,x) = x = f(x,unit)
.Vous pouvez créer un foncteur à
U
partir de la catégorie des monoïdes (où les flèches sont des homomorphismes monoïdes, c'est-à-dire qu'ils s'assurent qu'ils correspondentunit
àunit
l'autre monoïde et que vous pouvez composer avant ou après le mappage à l'autre monoïde sans changer de signification) à la catégorie d'ensembles (où les flèches ne sont que des flèches de fonction) qui «oublie» l'opération etunit
, et vous donne simplement l'ensemble de support.Ensuite, vous pouvez définir un foncteur
F
de la catégorie des ensembles à la catégorie des monoïdes qui reste adjointe à ce foncteur. Ce foncteur est le foncteur qui associe un ensemblea
au monoïde[a]
, oùunit = []
etmappend = (++)
.Donc, pour passer en revue notre exemple jusqu'à présent, en pseudo-Haskell:
Ensuite, pour montrer que
F
c'est gratuit, nous devons démontrer qu'il est laissé adjoint àU
, un foncteur oublieux, c'est-à-dire, comme nous l'avons mentionné ci-dessus, nous devons montrer queF a → b
est isomorphe àa → U b
maintenant, rappelez-vous que la cible de
F
est dans la catégorieMon
des monoïdes, où les flèches sont des homomorphismes monoïdes, nous avons donc besoin d'un pour montrer qu'un homomorphisme monoïde de[a] → b
peut être décrit précisément par une fonction dea → b
.Dans Haskell, nous appelons le côté de cela qui vit dans
Set
(euh,Hask
la catégorie de types Haskell que nous prétendons être Set), justefoldMap
, qui, lorsqu'elle est spécialisée deData.Foldable
à Lists, a du typeMonoid m => (a → m) → [a] → m
.Il y a des conséquences qui découlent de cette adjonction. Notamment, si vous oubliez, puis construisez avec free, puis oubliez à nouveau, c'est comme vous l'avez oublié une fois, et nous pouvons l'utiliser pour construire la jointure monadique. depuis
UFUF
~U(FUF)
~UF
, et nous pouvons passer dans l'homomorphisme monoïde d'identité de[a]
à[a]
travers l'isomorphisme qui définit notre adjonction, obtenir qu'un isomorphisme de liste[a] → [a]
est une fonction de typea -> [a]
, et c'est juste un retour pour les listes.Vous pouvez composer tout cela plus directement en décrivant une liste en ces termes avec:
La monade libre
Qu'est-ce qu'une Free Monad ?
Eh bien, nous faisons la même chose que nous faisions avant, nous commençons avec un foncteur oublieux U de la catégorie des monades où les flèches sont des homomorphismes de monade à une catégorie d'endofoncteurs où les flèches sont des transformations naturelles, et nous recherchons un foncteur qui est laissé adjoint pour que.
Alors, comment cela se rapporte-t-il à la notion de monade libre telle qu'elle est généralement utilisée?
Savoir que quelque chose est une monade libre,
Free f
vous dit que donner un homomorphisme de monade à partir deFree f -> m
, c'est la même chose (isomorphe à) que donner une transformation naturelle (un homomorphisme de foncteur) à partir def -> m
. Rappelez-vous queF a -> b
doit être isomorphe poura -> U b
que F soit laissé adjoint à U. U ici mappé des monades aux foncteurs.F est au moins isomorphe au
Free
type que j'utilise dans monfree
package sur le piratage.Nous pourrions également le construire dans une analogie plus étroite avec le code ci-dessus pour la liste gratuite, en définissant
Cofree Comonads
Nous pouvons construire quelque chose de similaire, en regardant l'adjoint de droite d'un foncteur oublieux en supposant qu'il existe. Un foncteur cofree est simplement / à droite adjoint / à un foncteur oublieux, et par symétrie, savoir que quelque chose est un comonad cofree revient à savoir que donner un homomorphisme comonad à partir de
w -> Cofree f
est la même chose que donner une transformation naturelle à partir dew -> f
.la source
La Free Monad (structure de données) est à la Monad (classe) comme la List (structure de données) à Monoid (classe): c'est l'implémentation triviale, où vous pouvez décider ensuite comment le contenu sera combiné.
Vous savez probablement ce qu'est une Monade et que chaque Monade a besoin d'une implémentation spécifique (respectant la loi de la Monade) de
fmap
+join
+return
oubind
+return
.Supposons que vous ayez un Functor (une implémentation de
fmap
) mais le reste dépend des valeurs et des choix effectués au moment de l'exécution, ce qui signifie que vous voulez pouvoir utiliser les propriétés Monad mais que vous souhaitez choisir les fonctions Monad par la suite.Cela peut être fait en utilisant la Free Monad (structure de données), qui enveloppe le Functor (type) de manière à ce que ce
join
soit plutôt un empilement de ces foncteurs qu'une réduction.Le réel
return
et celui quejoin
vous souhaitez utiliser peuvent désormais être donnés comme paramètres à la fonction de réductionfoldFree
:Pour expliquer les types, nous pouvons remplacer
Functor f
parMonad m
etb
par(m a)
:la source
Une monade libre Haskell est une liste de foncteurs. Comparer:
Pure
est analogue àNil
etFree
est analogue àCons
. Une monade gratuite stocke une liste de foncteurs au lieu d'une liste de valeurs. Techniquement, vous pouvez implémenter des monades gratuites en utilisant un type de données différent, mais toute implémentation doit être isomorphe à celle ci-dessus.Vous utilisez des monades gratuites chaque fois que vous avez besoin d'un arbre de syntaxe abstrait. Le foncteur de base de la monade libre est la forme de chaque étape de l'arbre de syntaxe.
Mon article , que quelqu'un a déjà lié, donne plusieurs exemples de la façon de construire des arbres de syntaxe abstraits avec des monades gratuites
la source
Je pense qu'un simple exemple concret sera utile. Supposons que nous ayons un foncteur
avec l'évidence
fmap
. Ensuite ,Free F a
est le type d'arbres dont les feuilles ont le typea
et dont les noeuds sont étiquetés avecOne
,Two
,Two'
etThree
.One
-les nœuds ont un enfant,Two
- etTwo'
-nodes ont deux enfants etThree
-nodes en ont trois et sont également étiquetés avec unInt
.Free F
est une monade.return
correspondx
à l'arbre qui n'est qu'une feuille avec une valeurx
.t >>= f
regarde chacune des feuilles et les remplace par des arbres. Lorsque la feuille a une valeur,y
elle remplace cette feuille par l'arbref y
.Un diagramme rend cela plus clair, mais je n'ai pas les moyens d'en dessiner facilement un!
la source