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
Your problem is that your
pushandpopare just ordinary, non-monadic function which you are trying to use in the monadic do-block. You are usingnextcorrectly, since you call it using thestatefunction, but as you probably noticed,stateonly works for the plainStatemonad and notStateT.We can implement a monad transformer version of
statelike this:And then use it in the
balancedfunction withpushandpop.The function is called like this:
Where
sis the initial string and[]is the initial stack.