2012-02-08 1 views
5

균형 브래킷 문제를 해결하려고합니다. 나는 연속적인 IO를하고 싶지 않고 getLine을 한 번 호출하여 결과 문자열을 파싱합니다. 따라서 문제를 해결하는 함수는 두 개의 다른 상태, 즉 입력 문자열의 소비되지 않은 부분과 대괄호 스택을 처리합니다.정상적인 모나 딕 함수를 모나드 변압기와 동일하게 만들기

내가 스택 조작하기위한 일부 기능을 설정하려면 : 그러나 나는 StateT 모나드에서 운영하고있어,

type Stack = String 

pop :: Stack -> (Char,Stack) 
pop (x:xs) = (x,xs) 

push :: Char -> Stack -> ((),Stack) 
push a xs = ((),a:xs) 

나는 상태 모나드에서 운영하고있어 경우 모든 좋은

balanced :: StateT Stack (State String) Bool 

스택에 모나드가 중복되지 않도록해야한다는 것을 알고 있습니다. 내가 푸시와 팝 정의를 단순화하는 방법을 좋아하기 때문에 나는 이렇게하고있다.

두 가지 문제 :

  1. 는 상관없이 내가 뭘 내가 푸시를 적용하고 StateT에 포함 된 스택에 팝업 할 수있는 방법을 찾을 수 없습니다.
  2. 나는 주요 기능 여기

에서이를 호출하는 방법을 아무 생각이

next :: String -> (Maybe Char,String) 
next ""  = (Nothing,[]) 
next (x:xs) = (Just x,xs) 

balanced = do 
      c <- lift (state next) 
      case c of 
       Nothing -> return True 
       Just c -> if elem c open 
         then (push c) >> balanced 
         else if elem c close 
           then pop >>= \x -> 
           if eq x c 
           then balanced 
           else return False 
           else balanced 
      where open = "<{([" 
       close = "])}>" 
       eq '(' ')' = True 
       eq '{' '}' = True 
       eq '<' '>' = True 
       eq '[' ']' = True 
       eq _ _ = False 
+0

내부 모나드에 대해 'State String'대신 'Reader String'을 사용해보십시오. – dflemstr

답변

7

귀하에 문제가 pushpop 그냥 평범한 있다는 것입니다 코드의 나머지 부분의 비 모나드 기능 당신은 모나드 do-block에서 사용하려고합니다. state 함수를 사용하여 호출 했으므로 next을 올바르게 사용하고 있지만 눈치 챘을 때 stateState 모나드에만 사용되며 StateT이 아닌 경우에만 사용할 수 있습니다.

stateT :: Monad m => (s -> (a, s)) -> StateT s m a 
stateT f = do 
    (x, s') <- gets f 
    put s' 
    return x 

을 그리고 pushpop으로 balanced 기능에서 사용 :

우리는 다음과 같이 state의 모나드 변압기 버전을 구현할 수 있습니다.

balanced :: StateT Stack (State String) Bool 
balanced = do 
      c <- lift (state next) 
      case c of 
       Nothing -> return True 
       Just c -> if elem c open 
         then (stateT $ push c) >> balanced 
         else if elem c close 
           then stateT pop >>= \x -> 
           if eq x c 
            then balanced 
            else return False 
           else balanced 
      where open = "<{([" 
       close = "])}>" 
       eq '(' ')' = True 
       eq '{' '}' = True 
       eq '<' '>' = True 
       eq '[' ']' = True 
       eq _ _ = False 

기능은 다음과 같이 호출됩니다

evalState (evalStateT balanced []) s 
s 초기 문자열

[]은 초기 스택입니다.