Haskell: Gefangen in der IO-Monade

7

Ich versuche, eine Datei mit der Funktion parseFile im Paket haskell-src-exts zu analysieren. Ich versuche, mit der Ausgabe von parseFile zu arbeiten, die natürlich IO ist, aber ich kann nicht herausfinden, wie man um das IO herumkommt. Ich habe eine Funktion liftIO gefunden, bin mir aber nicht sicher, ob das die Lösung in dieser Situation ist. Hier ist der Code unten.

%Vor%

Ich möchte nur die Funktion pMod für die Ausgabe von parseFile verwenden können. Beachten Sie, dass alle Typen und Datenkonstruktoren unter Ссылка wenn das hilft. Danke im Voraus!

    
user2548080 13.08.2013, 16:41
quelle

2 Antworten

16

Sobald es in IO ist, gibt es kein Entkommen.

Verwenden Sie fmap :

%Vor%

( addition :) Wie in eine großartige Antwort von Levi Pearson erklärt, gibt es auch

%Vor%

Aber das ist auch keine schwarze Magie. Überlegen Sie:

%Vor%

So kann Ihre Funktion auch als

geschrieben werden %Vor%

was auch immer Sie finden intuitiver (denken Sie daran, (.) hat die höchste Priorität, direkt unter der Funktion Anwendung) .

Übrigens ist das >>= return . f -Bit wie liftM ist tatsächlich implementiert, nur in do -notation; und es zeigt wirklich die Äquivalenz von fmap und liftM , denn für jede Monade sollte es gelten:

%Vor%     
Will Ness 13.08.2013, 17:00
quelle
14

Um eine allgemeinere Antwort zu geben als die von Will (die sicherlich korrekt und auf den Punkt gebracht wurde), heben Sie Operationen normalerweise in eine Monade auf, anstatt Werte herauszunehmen von ihnen, um reine Funktionen auf monadische Werte anzuwenden.

Es kommt vor, dass Monad s (theoretisch) eine bestimmte Art von Functor sind. Functor beschreibt die Klasse von Typen, die Zuordnungen von Objekten und Operationen in einem anderen Kontext darstellen. Ein Datentyp, der eine Instanz von Functor darstellt, ordnet Objekte über seine Datenkonstruktoren in den Kontext ein und ordnet Operationen über die Funktion fmap in den Kontext zu. Um einen echten Funktor zu implementieren, muss fmap so arbeiten, dass die Aufhebung der Identity-Funktion in den funktor-Kontext die Werte im funktor-Kontext nicht ändert und das Anheben von zwei zusammengesetzten Funktionen die gleiche Operation im funktor-Kontext wie lifting erzeugt die Funktionen separat und dann komponieren sie im Funktor Kontext.

Viele, viele Haskell-Datentypen bilden natürlich Funktoren, und fmap stellt eine universelle Schnittstelle zum Anheben von Funktionen bereit, so dass sie gleichmäßig auf alle Daten angewendet werden, ohne sich um die Form der jeweiligen Functor -Instanz kümmern zu müssen. Ein paar gute Beispiele hierfür sind der Listentyp und der Typ Maybe ; fmap einer Funktion in einen Listenkontext entspricht genau der bekannten map -Operation in Listen, und fmap einer Funktion in einem Maybe -Kontext übernimmt die Funktion normalerweise für einen Just a -Wert und do nichts für einen Wert Nothing , mit dem Sie Operationen ausführen können, ohne sich darum kümmern zu müssen.

Nachdem wir das alles gesagt haben, verlangt das Haskell-Präludium gegenwärtig nicht, dass Monad -Instanzen auch eine Functor -Instanz haben, also bietet Monad eine Familie von Funktionen, die Operationen auch in monadische Kontexte heben . Die Operation liftM bewirkt dasselbe wie fmap für Monad Instanzen, die auch Functor Instanzen sind (wie sie sein sollten). Aber fmap und liftM heben nur Funktionen mit einem Argument an. Monad stellt hilfreich eine Familie von liftM2 - liftM5 Funktionen zur Verfügung, die Funktionen mit mehreren Argumenten auf dieselbe Weise in den monadischen Kontext heben.

Schließlich haben Sie nach liftIO gefragt, was die verwandte Idee von monad Transformatoren beinhaltet, in der mehrere Monad Instanzen in einem einzigen Datentyp kombiniert werden, indem Monad-Mappings auf bereits monadische Werte, die eine Art Stapel von monadischen Abbildungen über einen reinen Grundtyp bilden. Die mtl -Bibliothek bietet eine Implementierung dieser allgemeinen Idee und definiert in ihrem Modul Control.Monad.Trans zwei Klassen, MonadTrans t und Monad m => MonadIO m . Die Klasse MonadTrans stellt eine einzige Funktion, lift , bereit, die Zugriff auf Operationen in der nächsthöheren monadischen "Schicht" im Stapel gibt, d. H.% Co_de%. Die Klasse (MonadTrans t, Monad m) => m a -> t m a stellt eine einzige Funktion zur Verfügung, MonadIO , die Zugriff auf liftIO monad-Operationen von jeder "Schicht" im Stapel bietet, d. H.% Co_de%. Dies macht das Arbeiten mit Monad-Transformer-Stacks wesentlich komfortabler, da viele Transformatoreninstanz-Deklarationen bereitgestellt werden müssen, wenn neue IO -Instanzen in einen Stack eingeführt werden.

    
Levi Pearson 13.08.2013 19:31
quelle

Tags und Links