2010-10-13 14 views
64

In welchen Situationen sollte liftIO verwendet werden? Wenn ich ErrorT String IO verwende, arbeitet die lift Funktion, um IO-Aktionen in ErrorT zu heben, so scheint liftIO überflüssig zu sein.Haskell: Aufzug vs LiftIO

Antwort

75

lift hebt immer von der "vorherigen" Schicht ab. Wenn Sie von der zweiten Schicht abheben müssen, benötigen Sie lift . lift und so weiter.

Auf der anderen Seite hebt liftIO immer von der IO-Schicht (die, wenn vorhanden, immer auf der Unterseite des Stapels ist). Also, wenn Sie mehr als 2 Schichten von Monaden haben, werden Sie schätzen liftIO.

den Typ des Arguments in den folgenden lambdas vergleichen.

type T = ReaderT Int (WriterT String IO) Bool 

> :t \x -> (lift x :: T) 
\x -> (lift x :: T) :: WriterT String IO Bool -> T 

> :t \x -> (liftIO x :: T) 
\x -> (liftIO x :: T) :: IO Bool -> T 
+26

Normalerweise werde ich 'liftIO' verwenden, um auf die IO-Ebene zu heben, auch wenn' lift' ausreichend ist, weil ich dann den Monad-Stack ändern kann und der Code immer noch funktioniert. –

+11

@John: guter Punkt. Und es macht auch deutlich, dass Sie IO und nicht irgendeine andere Monade heben. –

28

liftIO ist nur eine Verknüpfung zu dem IO Monade, je nachdem, was die Monade Sie sind im Grunde gleich liftIO eine variable Anzahl von Aufzügen zu verwenden . Das klingt zunächst überflüssig, aber die Verwendung von liftIO hat einen großen Vorteil: Es macht Ihren IO-Code unabhängig von der tatsächlichen Monad-Konstruktion, so dass Sie denselben Code wiederverwenden können, unabhängig von der Anzahl der Layer, aus denen Ihre endgültige Monade besteht beim Schreiben eines Monade-Transformators).

Auf der anderen Seite kommt LiftIO nicht kostenlos, wie Lift tut: die Monade-Transformatoren, die Sie verwenden, müssen Unterstützung dafür haben, z. Die Monade, in der Sie sich befinden, muss eine Instanz der MonadIO-Klasse sein, aber die meisten Monaden heutzutage (und natürlich prüft der Typ-Checker das zur Kompilierzeit für Sie: das ist die Stärke von Haskell!).