簡體   English   中英

使正常的monadic函數與monad變換器等效

[英]Making normal monadic functions work with the monad transformer equivalent

我正試圖解決平衡括號問題。 我不想做連續的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中包含的Stack的方法。
  2. 我不知道如何從main函數調用它

這是代碼的其余部分

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

你的問題是你的pushpop只是普通的非monadic函數,你試圖在monadic do-block中使用它。 您正在使用next正確的,因為您使用state函數調用它,但正如您可能注意到的, state僅適用於普通State monad而不適用於StateT

我們可以像這樣實現一個monad變換器版本的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是初始字符串, []是初始堆棧。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM