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!
Sobald es in IO ist, gibt es kein Entkommen.
Verwenden Sie fmap
:
( 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:
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.