Diese Frage bezieht sich auf diesen Artikel
Die Idee ist, eine DSL für das Manipulieren von Dateien in der Cloud zu definieren und ein Zusammensetzung von Dolmetschern, die sich um die verschiedenen Aspekte kümmern, wie z Kommunikation mit der REST-Schnittstelle und Protokollierung.
Um dies konkreter zu machen, nehmen wir an, dass wir die folgende Datenstruktur haben definiert die Bedingungen der DSL.
%Vor%Wir definieren Funktionen zum Erstellen von CloudFiles-Programmen wie folgt:
%Vor%Dann ist die Idee, dies in Bezug auf zwei andere DSLs zu interpretieren:
%Vor%Ich habe es geschafft, eine natürliche Transformation von der CloudFiles DSL zur REST DSL mit folgendem Typ:
%Vor%Dann gegeben ein Programm des Formulars:
%Vor%Es ist möglich, das Programm mit REST-Aufrufen wie folgt zu interpretieren:
%Vor%Das Problem kommt beim Versuch, eine Interpretation der DSL mit zu definieren protokollieren. In dem Artikel, den ich oben erwähnt habe, definiert der Autor einen Interpreter mit Typ:
%Vor% und wir definieren einen Interpreter für Free LogF a
vom Typ:
Das Problem ist, dass dieser Interpreter nicht in Kombination mit verwendet werden kann
foldFree
wie oben. Die Frage ist also, wie man ein Programm interpretiert
Free CloudFilesF a
mit der Funktion logCloudfilesI
und interpretLog
oben definiert? Im Grunde suche ich nach einer Funktion mit dem Typ:
Ich kann das mit dem REST DSL machen, aber ich kann es nicht usng logCloudfilesI
machen.
Was ist der Ansatz, wenn in diesen Situationen freie Monaden verwendet werden? Hinweis
das Problem scheint die Tatsache zu sein, dass es für den Fall der Protokollierung keine gibt
bedeutender Wert können wir der Funktion in ListFiles
liefern, um die
Fortsetzung des Programms. In einem zweiten Artikel
Der Autor verwendet Halt
jedoch
Dies funktioniert nicht in meiner aktuellen Implementierung .
Die Protokollierung ist ein klassischer Anwendungsfall für das Decorator-Muster.
Der Trick besteht darin, das Programm in einem Kontext zu interpretieren, der sowohl auf die Logging-Effekte als auch auf einen Basiseffekt zugreifen kann. Die Anweisungen in einer solchen Monade würden entweder Anweisungen für den Befehl oder vom Basis-Funktor protokollieren. Hier ist das Funktorkoprodukt , das im Grunde genommen " Either
für Funktoren" ist.
Wir müssen in der Lage sein, Programme von einer Basis-freien Monade in die freie Monade eines Koprodukt-Funktors zu injizieren.
%Vor% Jetzt haben wir genug Struktur, um den Logging Interpreter als Dekorator um einen anderen Interpreter zu schreiben. decorateLog
verschachtelt die Protokollierungsbefehle mit Anweisungen von einer beliebigen freien Monade und delegiert die Interpretation an eine Funktion CloudFiles f a -> Free f a
.
So decorateLog interpretCloudWithRest :: CloudFilesF a -> Free (LogF :+: RestF) a
ist ein Interpreter, der ein Programm ausgibt, dessen Befehlssatz aus Anweisungen von LogF
und RestF
besteht.
Jetzt müssen wir nur noch einen Interpreter (LogF :+: RestF) a -> IO a
schreiben, den wir aus interpLogIO :: LogF a -> IO a
und interpRestIO :: RestF a -> IO a
erstellen.
So foldFree interpLogRestIO :: Free (LogF :+: RestF) a -> IO a
wird die Ausgabe von decorateLog interpretCloudWithRest
in der IO
Monade ausführen. Der gesamte Compiler wird als foldFree interpLogRestIO . foldFree (decorateLog interpretCloudWithRest) :: Free CloudFilesF a -> IO a
geschrieben.
In seinem Artikel geht de Goes (ha ha) einen Schritt weiter und baut diese Coprodukt-Infrastruktur mit Prismen . Dies vereinfacht die Zusammenfassung über den Befehlssatz.
Der USP der extensible-effects
-Bibliothek ist, dass es all das Gerangel mit Funktor-Coprodukten für Sie automatisiert. Wenn du die kostenlose Monadroute verfolgst (persönlich bin ich nicht so begeistert wie de Goes), dann würde ich extensible-effects
empfehlen, anstatt dein eigenes Effektsystem zu rollen.
Tags und Links haskell logging functional-programming free-monad