Ich habe den Begriff gesehen Freie Monad Pop - up jeden jetzt und dann für einige Zeit, aber jeder scheint nur zu benutzen / diskutieren sie , ohne eine Erklärung zu geben , was sie sind. Also: Was sind freie Monaden? (Ich würde sagen, ich bin mit Monaden und den Grundlagen von Haskell vertraut, habe aber nur sehr grobe Kenntnisse der Kategorietheorie.)
haskell
monads
free-monad
David
quelle
quelle
Antworten:
Die Antwort von Edward Kmett ist offensichtlich großartig. Aber es ist ein bisschen technisch. Hier ist eine vielleicht zugänglichere Erklärung.
Kostenlose Monaden sind nur eine allgemeine Methode, um Funktoren in Monaden zu verwandeln. Das heißt, vorausgesetzt, jeder Funktor
f
Free f
ist eine Monade. Dies wäre nicht sehr nützlich, es sei denn, Sie erhalten zwei FunktionenMit der ersten können Sie in Ihre Monade "hineinkommen", und mit der zweiten können Sie "herauskommen".
Im Allgemeinen ist ein "freies X" eine Möglichkeit, von einem Y zu einem X zu gelangen, ohne etwas zu gewinnen, wenn X ein Y mit einigen zusätzlichen Dingen P ist.
Beispiele: Ein Monoid (X) ist eine Menge (Y) mit einer zusätzlichen Struktur (P), die im Grunde sagt, dass es eine Operation (Sie können sich eine Addition vorstellen) und eine Identität (wie Null) hat.
Damit
Jetzt kennen wir alle Listen
Nun, bei jedem Typ, den
t
wir kennen,[t]
ist das ein Monoidund so sind Listen das "freie Monoid" über Mengen (oder in Haskell-Typen).
Okay, freie Monaden sind die gleiche Idee. Wir nehmen einen Funktor und geben eine Monade zurück. In der Tat, da Monaden als Monoide in der Kategorie der Endofunktoren angesehen werden können, die Definition einer Liste
sieht der Definition von freien Monaden sehr ähnlich
und die
Monad
Instanz hat eine Ähnlichkeit mit derMonoid
Instanz für ListenJetzt bekommen wir unsere beiden Operationen
quelle
Free f a = Pure a | Roll (f (Free f a))
wieFree f a = a + fa + ffa + ...
, dh „f zu einem beliebig oft angewandt“. Dann nimmtconcatFree
(dhjoin
) ein "f, das beliebig oft auf (f wird beliebig oft auf a angewendet)" und reduziert die beiden verschachtelten Anwendungen zu einer. Und>>=
nimmt "f beliebig oft auf a angewendet" und "wie man von a nach kommt (b mit f beliebig oft angewendet)" und wendet letzteres im Grunde auf a innerhalb des ersteren an und kollabiert die Verschachtelung. Jetzt verstehe ich es selbst!concatFree
Grundejoin
?Hier ist eine noch einfachere Antwort: Eine Monade ist etwas, das "berechnet" wird, wenn der monadische Kontext durch reduziert wird
join :: m (m a) -> m a
(wobei daran erinnert wird, dass>>=
dies definiert werden kann alsx >>= y = join (fmap y x)
). So führen Monaden den Kontext durch eine sequentielle Kette von Berechnungen: Denn an jedem Punkt der Reihe wird der Kontext des vorherigen Aufrufs mit dem nächsten reduziert.Eine freie Monade erfüllt alle Monadengesetze, kollabiert jedoch nicht (dh berechnet). Es baut nur eine verschachtelte Reihe von Kontexten auf. Der Benutzer, der einen solchen freien monadischen Wert erstellt, ist dafür verantwortlich, etwas mit diesen verschachtelten Kontexten zu tun, sodass die Bedeutung einer solchen Komposition bis zur Erstellung des monadischen Werts verschoben werden kann.
quelle
Ein freies Foo ist zufällig die einfachste Sache, die alle 'Foo'-Gesetze erfüllt. Das heißt, es erfüllt genau die Gesetze, die notwendig sind, um ein Foo zu sein, und nichts Besonderes.
Ein vergesslicher Funktor ist einer, der einen Teil der Struktur "vergisst", wenn er von einer Kategorie zur anderen wechselt.
Gegebene Funktoren
F : D -> C
, undG : C -> D
wir sagenF -| G
,F
ist links nebenG
oderG
rechts neben,F
wann immer a, b:F a -> b
isomorph ista -> G b
, wo die Pfeile aus den entsprechenden Kategorien stammen.Formal bleibt ein freier Funktor neben einem vergesslichen Funktor.
Das freie Monoid
Beginnen wir mit einem einfacheren Beispiel, dem freien Monoid.
Nehmen Sie ein Monoid, das durch einen Trägersatz definiert ist
T
, eine binäre Funktion, um ein Elementpaar zusammenzufügenf :: T → T → T
, und aunit :: T
, so dass Sie ein assoziatives Gesetz und ein Identitätsgesetz haben :f(unit,x) = x = f(x,unit)
.Sie können einen Funktor machen
U
aus der Kategorie der Monoide (wo Pfeile Monoid Homomorphismen sind, das heißt, sie sicherstellen , dass sie Karteunit
zuunit
auf der anderen Monoid, und dass Sie vor oder nach der Abbildung auf die andere Monoid ohne Änderung Bedeutung komponieren kann) in die Kategorie von Sätzen (wobei Pfeile nur Funktionspfeile sind), die die Operation "vergessen"unit
und Ihnen nur den Trägersatz geben.Anschließend können Sie einen Funktor
F
aus der Kategorie der Sets zurück in die Kategorie der Monoide definieren, die neben diesem Funktor verbleibt. Dieser Funktor ist der Funktor, der eine Mengea
dem Monoid zuordnet[a]
, wounit = []
undmappend = (++)
.Um unser bisheriges Beispiel in Pseudo-Haskell zu überprüfen:
Dann, um zu zeigen,
F
ist kostenlos, müssen wir zeigen, dass es nebenU
einem vergesslichen Funktor bleibt, das heißt, wie wir oben erwähnt haben, müssen wir das zeigenF a → b
ist isomorph zua → U b
Denken Sie nun daran, dass das Ziel von
F
in der KategorieMon
der Monoide liegt, in der Pfeile Monoidhomomorphismen sind. Wir müssen also zeigen, dass ein Monoidhomomorphismus von[a] → b
durch eine Funktion von genau beschrieben werden kanna → b
.In Haskell nennen wir die Seite davon, in der wir leben
Set
(ähm,Hask
die Kategorie der Haskell-Typen, die wir vorgeben, ist Set), nurfoldMap
die, wenn sie vonData.Foldable
auf Listen spezialisiert ist, Typ hatMonoid m => (a → m) → [a] → m
.Daraus ergeben sich Konsequenzen als Ergänzung. Insbesondere, wenn Sie vergessen, dann bauen Sie mit kostenlos auf, dann vergessen Sie wieder, es ist genau so, wie Sie es einmal vergessen haben, und wir können dies verwenden, um den monadischen Join aufzubauen. da
UFUF
~U(FUF)
~UF
und wir den identitätsmonoiden Homomorphismus von[a]
bis[a]
durch den Isomorphismus übergeben können, der unsere Adjunktion definiert, erhalten Sie, dass ein Listenisomorphismus von[a] → [a]
eine Funktion des Typs ista -> [a]
, und dies ist nur eine Rückgabe für Listen.Sie können dies alles direkter zusammenstellen, indem Sie eine Liste folgendermaßen beschreiben:
Die freie Monade
Was ist also eine freie Monade? ?
Nun, wir machen das Gleiche wie zuvor. Wir beginnen mit einem vergesslichen Funktor U von der Kategorie der Monaden, bei der Pfeile Monadenhomomorphismen sind, zu einer Kategorie von Endofunktoren, bei denen die Pfeile natürliche Transformationen sind, und suchen nach einem Funktor, der nebeneinander bleibt dazu.
Wie hängt das mit der Vorstellung einer freien Monade zusammen, wie sie normalerweise verwendet wird?
Zu wissen, dass etwas eine freie Monade ist
Free f
, sagt Ihnen, dass das Geben eines Monadenhomomorphismus vonFree f -> m
dasselbe ist (isomorph zu) wie das Geben einer natürlichen Transformation (eines Funktorhomomorphismus) vonf -> m
. Denken Sie daran,F a -> b
dass es isomorph zu sein muss,a -> U b
damit F neben U bleibt. Hier werden Monaden auf Funktoren abgebildet.F ist mindestens isomorph zu dem
Free
Typ, den ich in meinemfree
Paket für Hackage verwende.Wir könnten es auch in engerer Analogie zum obigen Code für die freie Liste konstruieren, indem wir es definieren
Kaffeefreie Comonaden
Wir können etwas Ähnliches konstruieren, indem wir den richtigen Zusatz zu einem vergesslichen Funktor betrachten, vorausgesetzt, er existiert. Ein Cofree-Funktor ist einfach / richtig neben einem vergesslichen Funktor, und aus Symmetriegründen ist das Wissen, dass etwas eine Cofree-Comonade ist, dasselbe wie das Wissen, dass das Geben eines Comonad-Homomorphismus aus
w -> Cofree f
dasselbe ist wie das Geben einer natürlichen Transformation vonw -> f
.quelle
Die freie Monade (Datenstruktur) ist für die Monade (Klasse) wie die Liste (Datenstruktur) für die Monoid (Klasse): Es ist die triviale Implementierung, bei der Sie anschließend entscheiden können, wie der Inhalt kombiniert werden soll.
Sie wissen wahrscheinlich, was eine Monade ist und dass jede Monade eine spezifische (monadengesetzliche) Implementierung von beiden benötigt
fmap
+join
+return
oderbind
+ benötigtreturn
.Nehmen wir an, Sie haben einen Functor (eine Implementierung von
fmap
), aber der Rest hängt von den zur Laufzeit getroffenen Werten und Auswahlmöglichkeiten ab. Dies bedeutet, dass Sie die Monad-Eigenschaften verwenden möchten, aber anschließend die Monad-Funktionen auswählen möchten.Dies kann mit der Free Monad (Datenstruktur) erfolgen, die den Functor (Typ) so umschließt, dass
join
es sich eher um eine Stapelung dieser Funktoren als um eine Reduzierung handelt.Das Real
return
und das, wasjoin
Sie verwenden möchten, können nun als Parameter für die Reduktionsfunktion angegeben werdenfoldFree
:Um die Art zu erklären, können wir ersetzen
Functor f
mitMonad m
undb
mit(m a)
:quelle
Eine Haskell-freie Monade ist eine Liste von Funktoren. Vergleichen Sie:
Pure
ist analog zuNil
undFree
ist analog zuCons
. Eine kostenlose Monade speichert eine Liste von Funktoren anstelle einer Liste von Werten. Technisch gesehen könnten Sie freie Monaden mit einem anderen Datentyp implementieren, aber jede Implementierung sollte isomorph zu der obigen sein.Sie verwenden kostenlose Monaden, wenn Sie einen abstrakten Syntaxbaum benötigen. Der Basisfunktor der freien Monade ist die Form jedes Schritts des Syntaxbaums.
Mein Beitrag , den bereits jemand verlinkt hat, enthält einige Beispiele für das Erstellen abstrakter Syntaxbäume mit freien Monaden
quelle
Ich denke, ein einfaches konkretes Beispiel wird helfen. Angenommen, wir haben einen Funktor
mit dem Offensichtlichen
fmap
. DannFree F a
ist die Art der Bäume , deren Blätter haben Arta
und deren Knoten sind verschlagwortet mitOne
,Two
,Two'
undThree
.One
-Knoten haben ein Kind,Two
- undTwo'
-Knoten haben zwei Kinder undThree
-Knoten haben drei und sind auch mit einem gekennzeichnetInt
.Free F
ist eine Monade.return
wirdx
dem Baum zugeordnet, der nur ein Blatt mit Wert istx
.t >>= f
schaut auf jedes der Blätter und ersetzt sie durch Bäume. Wenn das Blatt einen Werty
hat, ersetzt es dieses Blatt durch den Baumf y
.Ein Diagramm macht dies klarer, aber ich habe nicht die Möglichkeit, einfach eines zu zeichnen!
quelle