使普通的一元函数与等效的一元转换器一起工作
我正在尝试解决平衡括号问题。我不想进行连续的 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。我这样做是因为我喜欢它如何简化推送和弹出定义。
两个问题:
- 无论我做什么,我都找不到将push和pop应用于 StateT 中包含的堆栈。
- 我不知道如何从主函数中调用它
这是其余的代码
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
I'm trying to solve the balanced brackets problem. I don't want to do continuous IO, and would rather make a single call to getLine and parse the resulting string. Therefore the function that solves the problem will deal with two different states: The unconsumed part of the input string, and the bracket stack.
I want to set up some functions for manipulating a stack:
type Stack = String
pop :: Stack -> (Char,Stack)
pop (x:xs) = (x,xs)
push :: Char -> Stack -> ((),Stack)
push a xs = ((),a:xs)
That's all good if I'm operating in the state monad, however I'm operating in the StateT monad
balanced :: StateT Stack (State String) Bool
I know I've been told not to have duplicate monads in the stack. I'm doing it this way because I like how it simplifies the push and pop definitions.
Two problems:
- No matter what I do I can't find a way to apply push and pop to the
Stack contained in the StateT. - I have no idea how to call this from the main function
Here's the rest of the code
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的问题是您的
push
和pop
只是普通的非单子函数,您试图在单子 do 块中使用它们。您正确使用了next
,因为您使用state
函数调用它,但正如您可能注意到的那样,state
仅适用于普通的State
monad 而不是StateT
。我们可以像这样实现
state
的 monad 转换器版本:然后在
balanced
函数中使用push
和pop.
该函数的调用方式如下:
其中
s
是初始字符串,[]
是初始堆栈。Your problem is that your
push
andpop
are just ordinary, non-monadic function which you are trying to use in the monadic do-block. You are usingnext
correctly, since you call it using thestate
function, but as you probably noticed,state
only works for the plainState
monad and notStateT
.We can implement a monad transformer version of
state
like this:And then use it in the
balanced
function withpush
andpop
.The function is called like this:
Where
s
is the initial string and[]
is the initial stack.