Problem polega na tym, że Maybe
nie jest częścią twojego stosu transformatora. Jeśli twój transformator wie tylko o StateT Int
i IO
, nie wie nic o tym, jak podnieść Maybe
.
Można to naprawić zmieniając typ T
do czegoś podobnego:
type T = StateT Int (MaybeT IO) Int
(Będziesz musiał importować Control.Monad.Trans.Maybe
).
Potrzebny będzie również zmienić swoją wewnętrzną do
pracować MaybeT
zamiast Maybe
. Oznacza to, owijając surowe Maybe a
wartości z MaybeT . return
:
f :: T
f = do
x <- get
val <- lift $ do
val <- MaybeT $ return someMaybe
-- more code in Maybe monad
return 4
return 3
Jest to trochę niewygodne, więc prawdopodobnie chcesz napisać funkcję jak liftMaybe
:
liftMaybe = MaybeT . return
Jeśli użyto lift
podnieść IO a
wartości w innych części twojego kodu, teraz to się zepsuje, ponieważ masz teraz trzy poziomy w stosie transformatora. Dostaniesz błąd, który wygląda tak:
Couldn't match expected type `MaybeT IO t0'
with actual type `IO String'
Aby rozwiązać ten problem, należy użyć liftIO
dla wszystkich surowców IO a
wartości. Wykorzystuje to działania typeklass do życia przez dowolną liczbę warstw transformatora.
W odpowiedzi na Twój komentarz: jeśli masz tylko kawałek kodu w zależności od Maybe
, łatwiej byłoby po prostu umieścić wynik notacji do
do zmiennej i meczu przeciwko że:
let maybeVal = do val <- someMaybe
-- more Maybe code
return 4
case maybeVal of
Just res -> ...
Nothing -> ...
Oznacza to, że kod Maybe
nie będzie w stanie wykonać operacji wejścia/wyjścia. Oczywiście możesz także użyć funkcji takiej jak fromMaybe
zamiast case
.
Chcesz kod w wewnętrznej 'do' uruchomić tylko w' Maybe' monady, czy też potrzebują dostępu do ' StateT Int' i 'IO' też? – pat
Tylko moneta "Maybe". – Adrian