2012-02-08 6 views
5

バランスブラケットの問題を解決しようとしています。私は連続IOをしたくないので、むしろgetLineを1回呼び出して、結果の文字列を解析します。したがって、問題を解決する関数は、2つの異なる状態、すなわち入力文字列の消費されていない部分とブラケットスタックを処理します。通常のモナディック関数をモナド変圧器と同等にする

私は、スタック操作するためのいくつかの機能を設定したい:しかし、私は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 

私はスタックに重複したモナドを持たないように言われてきたことは分かっています。私はそれがプッシュとポップの定義を単純化する方法が好きなので、この方法でやっています。

2つの問題:

  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

内側モナドの「状態文字列」の代わりに「リーダー文字列」を使用してみてください。 – dflemstr

答えて

7

あなたの問題はあなたのpushpopが普通であるということですコードの残りの部分だ、非モナド関数あなたはモナドのdo-blockで使用しようとしています。 state関数を使用して呼び出すので、nextを正しく使用していますが、おそらく気付いたように、stateStateのモナールでのみ使用でき、StateTでは使用できません。

私たちは、このようstateのモナド変換子バージョンを実装することができます

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

そしてpushpopbalanced機能でそれを使用します。

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が最初の文字列である

[]は初期スタックです。

関連する問題