In welchen Situationen sollte liftIO
verwendet werden? Wenn ich verwende ErrorT String IO
, lift
funktioniert die Funktion zum Aufheben von E / A-Aktionen ErrorT
und liftIO
erscheint daher überflüssig.
haskell
monad-transformers
Lachlan
quelle
quelle
liftIO
, um auf die E / A-Ebene zu heben, auch wenn dieslift
ausreicht, da ich dann den Monadenstapel ändern kann und der Code immer noch funktioniert.lift
In dieser Antwort (und der Frage) wird angenommen, dass sie von stammtControl.Monad.Trans.Class
, denke ich? Nicht dasMonadic lifting
oder das allgemeine Heben wie im ersten Abschnitt hier beschrieben ?liftIO ist nur eine Abkürzung zur E / A-Monade, unabhängig davon, in welcher Monade Sie sich befinden. Grundsätzlich entspricht liftIO der Verwendung einer variablen Anzahl von Aufzügen. Das mag zunächst redundant klingen, aber die Verwendung von liftIO hat einen großen Vorteil: Ihr IO-Code ist unabhängig von der tatsächlichen Monad-Konstruktion, sodass Sie denselben Code unabhängig von der Anzahl der Ebenen, aus denen Ihre endgültige Monad erstellt wurde, wiederverwenden können (dies ist sehr wichtig) beim Schreiben eines Monadentransformators).
Auf der anderen Seite ist liftIO nicht kostenlos, wie es lift ist: Die Monad-Transformatoren, die Sie verwenden, müssen Unterstützung dafür haben, z. B. muss die Monade, in der Sie sich befinden, eine Instanz der MonadIO-Klasse sein, aber die meisten Monaden heutzutage (Und natürlich überprüft der Typprüfer dies beim Kompilieren für Sie: Das ist die Stärke von Haskell!).
quelle
Alle vorherigen Antworten erklären den Unterschied recht gut. Ich wollte nur ein wenig Licht in das Innenleben bringen, damit es leichter zu verstehen
liftIO
ist, dass etwas nicht magisch ist (für die unerfahrenen Haskeller wie mich).liftIO :: IO a -> m a
ist ein weises Werkzeug, auf dem man einfach aufbauen kann
lift :: (Control.Monad.Trans.Class.MonadTrans t, Monad m) => m a -> t m a
und am häufigsten verwendet, wenn die untere Monade ist
IO
. Für dieIO
Monade ist die Definition recht einfach.class (Monad m) => MonadIO m where liftIO :: IO a -> m a instance MonadIO IO where liftIO = id
So einfach ...
liftIO
ist in der Tat nurid
für dieIO
Monade und im GrundeIO
die einzige, die unter die Definition der Typklasse fällt.Die Sache ist, wenn wir einen Monadentyp haben, der aus mehreren Schichten von Monadentransformatoren besteht
IO
, haben wir besser eineMonadIO
Instanz für jede dieser Monadentransformatorschichten. Zum Beispiel desMonadIO
von BeispielMaybeT m
erfordertm
von seinMonadIO
als auch typeclass.Das Schreiben einer
MonadIO
Instanz ist im Grunde auch eine sehr einfache Aufgabe. DennMaybeT m
es ist definiert wieinstance (MonadIO m) => MonadIO (MaybeT m) where liftIO = lift . liftIO
oder für
StateT s m
instance (MonadIO m) => MonadIO (StateT s m) where liftIO = lift . liftIO
Sie sind alle gleich. Stellen Sie sich vor, wenn Sie einen 4-Schicht-Transformatorstapel haben, müssen Sie dies entweder tun
lift . lift . lift . lift $ myIOAction
oder nurliftIO myIOAction
. Wenn Sie darüber nachdenken,lift . liftIO
bringt Sie jeder eine Ebene nach unten in den Stapel, bis er bis zu dem Punkt gräbt,IO
an dem erliftIO
definiert ist,id
und mit demselben Code wie oben zusammengesetztlift
endet.Dies ist im Grunde der Grund, warum unabhängig von der Konfiguration des Transformatorstapels alle darunter liegenden Schichten Mitglieder sind
MonadIO
undMonadTrans
eine einzigeliftIO
in Ordnung ist.quelle