Il problema è che Maybe
non fa parte dello stack del trasformatore. Se il tuo trasformatore conosce solo StateT Int
e IO
, non sa nulla su come sollevare Maybe
.
È possibile risolvere questo problema modificando il tipo di T
a qualcosa di simile:
type T = StateT Int (MaybeT IO) Int
(Avrai bisogno di importare Control.Monad.Trans.Maybe
.)
Sarà inoltre necessario cambiare il vostro interno do
di lavorare con MaybeT
anziché Maybe
. Questo significa avvolgere prime Maybe a
valori con MaybeT . return
:
f :: T
f = do
x <- get
val <- lift $ do
val <- MaybeT $ return someMaybe
-- more code in Maybe monad
return 4
return 3
Questo è un po 'imbarazzante, quindi probabilmente si vuole scrivere una funzione come liftMaybe
:
liftMaybe = MaybeT . return
Se è stato utilizzato lift
di sollevare IO a
valori in altri parti del tuo codice, questo verrà interrotto perché hai ora tre livelli nella tua pila di trasformatori. Si otterrà un errore che assomiglia a questo:
Couldn't match expected type `MaybeT IO t0'
with actual type `IO String'
Per risolvere questo problema, è necessario utilizzare liftIO
per tutte le vostre prime IO a
valori. Questo utilizza un typeclass per le azioni di vita IO
attraverso un numero qualsiasi di livelli di trasformatore.
In risposta al tuo commento: se hai solo un po 'di codice a seconda Maybe
, sarebbe più facile solo per mettere il risultato della notazione do
in una variabile e partita contro che:
let maybeVal = do val <- someMaybe
-- more Maybe code
return 4
case maybeVal of
Just res -> ...
Nothing -> ...
Ciò significa che il codice Maybe
non sarà in grado di eseguire un IO. È anche possibile utilizzare naturalmente una funzione come fromMaybe
anziché case
.
Vuoi il codice interno 'do' per eseguire solo nel Maybe' Monade', o ha bisogno di accedere al ' StateT Int' e 'IO' too? – pat
Solo 'Forse' Monade. – Adrian