[英]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。 我這樣做是因為我喜歡它如何簡化推送和流行定義。
兩個問題:
這是代碼的其余部分
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
你的問題是你的push
和pop
只是普通的非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
然后在push
和pop
的balanced
功能中使用它。
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.