Das Problem ist, dass Maybe
nicht Teil Ihres Transformatorstacks ist. Wenn Ihr Transformator nur über StateT Int
und IO
weiß, weiß es nichts über das Heben von Maybe
.
Sie können dieses Problem beheben, indem Sie Ihre Art T
etwas wie das Ändern:
type T = StateT Int (MaybeT IO) Int
(Sie werden Control.Monad.Trans.Maybe
importieren.)
Sie müssen auch Ihre innere do
ändern, mit zu arbeiten MaybeT
anstatt Maybe
. Dies bedeutet, rohe Maybe a
Werte mit MaybeT . return
Verpackung:
f :: T
f = do
x <- get
val <- lift $ do
val <- MaybeT $ return someMaybe
-- more code in Maybe monad
return 4
return 3
Dies ist ein wenig umständlich, so dass Sie wahrscheinlich eine Funktion wie liftMaybe
schreiben wollen:
liftMaybe = MaybeT . return
Wenn Sie verwendet lift
IO a
Werte in anderen zu heben Teile Ihres Codes, dies wird jetzt brechen, weil Sie jetzt drei Ebenen in Ihrem Transformator-Stack haben. Sie erhalten eine Fehlermeldung erhalten, die wie folgt aussieht:
Couldn't match expected type `MaybeT IO t0'
with actual type `IO String'
Um dies zu beheben, sollten Sie liftIO
für alle rohen IO a
Werte verwenden. Dies verwendet eine Typenklasse zum Leben IO
Aktionen durch eine beliebige Anzahl von Transformatorschichten.
Als Antwort auf Ihren Kommentar: Wenn Sie nur ein Stück Code auf Maybe
je haben, wäre es einfacher, nur das Ergebnis der do
Notation in eine Variable und Spiel gegen das setzen:
let maybeVal = do val <- someMaybe
-- more Maybe code
return 4
case maybeVal of
Just res -> ...
Nothing -> ...
Dies bedeutet, dass der Code Maybe
keinen IO ausführen kann. Sie können natürlich auch eine Funktion wie fromMaybe
anstelle von case
verwenden.
Haben Sie den Code in der inneren 'do' wollen nur im' Maybe' Monade laufen, oder es muss Zugriff auf die ' StateT Int' und 'IO' auch? – pat
Nur 'Maybe' Monade. – Adrian