2013-03-25 12 views
9

Diciamo che ho un monadT:Perché non è necessario utilizzare 'lift' quando si interagisce con un monotT StateT nidificato in questo caso?

type Wrap a = ReaderT Env (StateT Int (StateT Int Identity)) a 

La cosa importante da notare qui è che uno StateT è avvolgente altro, ed entrambi sono avvolti all'interno di una terza MonadT, vale a dire ReaderT.

e la funzione runWrap corrispondente per convenienza:

type Env = Map.Map Char Integer 

runWrap :: Env -> Int -> Int -> Wrap a -> a 
runWrap env st1 st2 m = runIdentity $ evalStateT (evalStateT (runReaderT m env) st2) st1 

E un generico monade Stato tock:

tock :: (Num s, MonadState s m) => m() 
tock = do modify (+1) 

ora creare un monadT involucro al cui interno io uso tock:

aWrap :: Wrap (Int, Int) 
aWrap = do 
    lift tock 
    lift . lift $ tock 
    x <- get 
    y <- lift . lift $ get 
    return (x, y) 

ed eseguirlo:

env = Map.fromList [('x', 1)] 
runWrap env 1 200 aWrap 
// answer: (201,2) 

L'uso di lift qui ha senso per me in termini della mia comprensione di come interagire con layer nidificati di MonadT.

Tuttavia, questo funziona anche e mi danno la stessa risposta: (201,2):

aWrap :: Wrap (Int, Int) 
aWrap = do 
    tock 
    lift . lift $ tock 
    x <- get 
    y <- lift . lift $ get 
    return (x, y) 

penserei chiamando tock w/o lift, si legge come se tock viene applicato al MonadT esterno, vale a dire ReaderT , il che non ha senso Ma perché funziona?

P.S. Si prega di ignorare la presenza di Env qui, non ha nulla a che fare con la domanda, solo la scelta del Monade esterno che sto usando.

risposta

8

Probabilmente stai usando la classe MonadState senza esserne consapevole. Questo typeclass è definito nel pacchetto mtl (e anche in monads-fd).

MonadState consente di utilizzare i metodi della monad State, direttamente e senza sollevamento esplicito, in molti stack monad basati su State.

un'occhiata alle seguenti due righe nel haddocks:

Monad m => MonadState s (StateT s m) 
MonadState s m => MonadState s (ReaderT r m) 

Il primo dice che qualsiasi StateT è un'istanza di MonadState (come dovremmo aspettarci!). Il secondo dice che qualsiasi ReaderT la cui monade di base è un'istanza di MonadState, è anche un'istanza di MonadState. Il caso è il tuo caso.

Guardando il source code per MonadState, troviamo:

instance MonadState s m => MonadState s (ReaderT r m) where 
    get = lift get 
    put = lift . put 
    state = lift . state 

modify :: MonadState s m => (s -> s) -> m() 
modify f = state (\s -> ((), f s)) 

Come si vede, il meccanismo interno del typeclass si occupa del sollevamento.

Esistono altri tipi di caratteri che offrono funzionalità simili, ad esempio MonadReader, MonadWriter e MonadRWS.

Problemi correlati