2013-03-25 3 views
9

의가 나는 monadT 있다고 가정 해 봅시다.이 경우 중첩 된 StateT 모나드와 상호 작용할 때 'lift'를 사용해야하는 이유는 무엇입니까?</p> <pre><code>type Wrap a = ReaderT Env (StateT Int (StateT Int Identity)) a </code></pre> <p>여기서 주목해야 할 중요한 것은 하나 StateT 다른 포장되며, 모두 제 3 MonadT, 즉 ReaderT 내부에 포장되어 있습니다 :

과 편의를 위해 해당 runWrap 기능 :

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 

을 그리고 일반적인 째깍 상태 모나드 :

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

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

내가 지금은 째깍를 사용하여 내부 랩 monadT를 만들

그리고 실행하십시오 :

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

MonadT의 중첩 된 레이어와 상호 작용하는 방법에 대한 나의 이해 측면에서 여기에 lift을 사용하는 것이 좋습니다.

그러나,이 또한 작동하고 나에게 같은 대답 제공 : tock는 외부 MonadT, 즉 ReaderT에 적용되는 것처럼 lift O를, 그것을 읽고 승/tock를 호출하여

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

내가 생각 : (201,2)를 , 그것은 말이 안된다. 그러나 이것이 왜 효과가 있습니까?

P. 여기에 Env의 존재를 무시하십시오, 그것은/질문, 내가 사용하는 바깥 쪽의 MonadT의 선택과 아무 상관이 없습니다.

답변

8

알고 계시지 만 MonadState 타입 클레임을 사용하고 계신 것 같습니다. 이 typecass는 mtl 패키지 (및 monads-fd에도 있음)에 정의되어 있습니다.

MonadStateState을 기반으로하는 많은 모나드 스택에서 State 모나드의 메서드를 직접적으로 그리고 명시 적으로 해제하지 않고 사용할 수 있습니다. haddocks에서 다음 두 줄에서

봐 :

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

첫 번째는 어떤 StateTMonadState의 인스턴스 인 것을 말한다 (우리가 기대해야으로!). 두 번째 것은 기본 모나드가 MonadState의 인스턴스 인 ReaderTMonadState의 인스턴스라고합니다. 어떤 경우에 당신의 경우입니다. MonadStatesource code 보면

, 우리는 발견 : 보시다시피

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)) 

의 typeclass의 내부 기계 리프팅을 담당한다.

MonadReader, MonadWriterMonadRWS과 같은 유사한 기능을 제공하는 다른 유형의 안경이 있습니다.