Was ich in der Regel wird sie mit, was ich Transformator Monad Klassen genannt haben:
{-# LANGUAGE FlexibleContexts #-}
import Control.Monad.Reader
import Control.Monad.State
inner :: ReaderT Char IO Int
inner = do
a <- ask
lift $ print a
return 5
inner' :: (MonadReader Char m, MonadIO m) => m Int
inner' = do
a <- ask
liftIO $ print a
return 5
outer :: StateT Char (ReaderT Char IO) Int
outer = do
a <- get
b <- lift $ inner -- need to lift
c <- inner' -- no need to lift
lift . lift $ print "need to lift twice to get to IO"
return 5
main = runReaderT (runStateT outer 'b') 'a'
Lassen Sie uns es brechen; Die erste inner
Funktion hat einen konkreten Typ, den Sie direkt anheben müssen, um es zu benutzen. Wenn Sie jedoch nur Fähigkeiten in der Signatur parametrisieren, können Sie das Heben überspringen, solange es im Stapel eindeutig ist, wo diese Fähigkeit erhalten wird. In diesem Fall ist es klar, denn StateT Char (ReaderT Char IO) Int
hat genau eine Instanz für MonadIO
(aus IO
) und genau eine Instanz von MonadReader Char
(aus ReaderT ... Char
).
Jetzt ist es egal wie viele hebt Sie müssen machen, solange die Instanz klar ist! Bedenken Sie:
outer' :: ErrorT String (StateT Char (ReaderT Char IO)) Int
outer' = do
a <- inner' -- still no need to lift!
b <- lift . lift $ inner -- need to double lift in this case
return 5
Das letzte, was nicht offensichtlich sein könnte, ist, dass die Unterschrift von outer
könnte auch in allgemeiner Weise ausgedrückt werden:
outer :: (MonadState Char m, MonadReader Char m, MonadIO m) => m Int
Und es würde immer noch funktionieren ohne Aufzüge (gut sans liftIO
für IO-Operationen, da Funktionen wie print
werden in Form von IO
definiert, nicht MonadIO m
. im Vergleich dazu Funktionen wie ask
und get
in Bezug auf die jeweiligen MonadX
Klasse definiert sind, die uns th überspringen erlaubt e Heben).
können Sie bitte ein Beispiel hinzufügen, wo Sie * 'foo' in' bar' anrufen - brauchen Sie wahrscheinlich nur den richtigen * Lift *? – Carsten
Ja, vielen Dank. Ich habe 'lift $ lift $' benutzt und der Compiler hat es akzeptiert. Ich wusste es nicht - ich dachte, dass der Lift automatisch gemacht wird. –
gut das würde die Verwendung von Monad-Stacks viel einfacher machen;) - aber egal - vielleicht möchten Sie Ihre eigene Antwort schreiben oder die Frage schließen, wenn es für Sie gelöst ist – Carsten