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:
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
All monad transformers are instances of MonadTrans , and so lift is available for them all. There is a variant of lift specific to IO operations, called liftIO , which is the single method of the MonadIO class in Control. Monad. IO.
A monadic function is a function with a single argument, written to its right. It is one of three possible function valences; the other two are dyadic and niladic. The term prefix function is used outside of APL to describe APL's monadic function syntax.
What is a Monad? A monad is an algebraic structure in category theory, and in Haskell it is used to describe computations as sequences of steps, and to handle side effects such as state and IO. Monads are abstract, and they have many useful concrete instances. Monads provide a way to structure a program.
liftIO allows us to lift an IO action into a transformer stack that is built on top of IO and it works no matter how deeply nested the stack is.
Your problem is that your push
and pop
are just ordinary, non-monadic function which you are trying to use in the monadic do-block. You are using next
correctly, since you call it using the state
function, but as you probably noticed, state
only works for the plain State
monad and not StateT
.
We can implement a monad transformer version of state
like this:
stateT :: Monad m => (s -> (a, s)) -> StateT s m a
stateT f = do
(x, s') <- gets f
put s'
return x
And then use it in the balanced
function with push
and 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
The function is called like this:
evalState (evalStateT balanced []) s
Where s
is the initial string and []
is the initial stack.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With