使正常的monadic函数与monad变换器等效

时间:2012-02-08 06:07:25

标签: parsing haskell stack monads monad-transformers

我正在尝试解决平衡括号问题。我不想做连续的IO,宁愿只调用getLine并解析生成的字符串。因此,解决问题的函数将处理两种不同的状态:输入字符串的未消耗部分和括号堆栈。

我想设置一些操作堆栈的函数:

type Stack = String

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

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

如果我在州monad运营,那就好了,不过我在StateT monad中运营

balanced :: StateT Stack (State String) Bool

我知道我被告知不要在堆栈中有重复的monad。我这样做是因为我喜欢它如何简化推送和流行定义。

两个问题:

  1. 无论我做什么,我找不到一种方法来应用push和pop 包含在StateT中的堆栈。
  2. 我不知道如何从主函数
  3. 中调用它

    这是代码的其余部分

    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
    

1 个答案:

答案 0 :(得分:7)

你的问题是你的pushpop只是普通的非monadic函数,你试图在monadic do-block中使用它。您正在使用next,因为您使用state函数调用它,但正如您可能已经注意到的那样,state仅适用于普通State monad而不是{{1} }}

我们可以像这样实现StateT的monad变换器版本:

state

然后在stateT :: Monad m => (s -> (a, s)) -> StateT s m a stateT f = do (x, s') <- gets f put s' return x 函数balancedpush中使用它。

pop

该函数的调用如下:

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是初始堆栈。