Popping from a list in state while a condition is true I'm dealing with data that stores its state as a String, treating the string like a stack. I also have to combine that with error handling.

To that end, I'm using the type StateT String Maybe a. I have a function to pop and to push a Char from and to the string:

pop :: StateT String Maybe Char
pop = do
    x:xs &lt;- get
    put xs
    return x

push :: Char -&gt; StateT String Maybe ()
push x = do
    xs &lt;- get
    put (x:xs)
    return ()


I wrote a function to repeatedly pop from the string while the characters being popped fulfilled a condition. It behaves as follows:

&gt; runStateT (popWhile (&lt;'a')) "HELLO world"
Just ("HELLO ","world")

&gt; runStateT (popWhile (&gt;'a')) "HELLO world"
Just ("","HELLO world")


My implementation is the following:

popWhile :: (Char -&gt; Bool) -&gt; StateT String Maybe [Char]
popWhile f = do
    s &lt;- get
    if null s
        then return []
        else popAgain

    where
        popAgain = do
            x &lt;- pop
            if f x
                then liftM (x:) (popWhile f)
                else push x &gt;&gt; return []


But that seems pretty bulky, and has two if then else's in it. Is there a better way to write this function?
You can simplify the code by using span:


  span :: (a -&gt; Bool) -&gt; [a] -&gt; ([a], [a])
  
  span, applied to a predicate p and a list xs, returns a tuple where
  first element is longest prefix (possibly empty) of xs of elements
  that satisfy p and second element is the remainder of the list


popWhile :: (Char -&gt; Bool) -&gt; StateT String Maybe String
popWhile p = do
    s &lt;- get
    let (xs, ys) = span p s
    put ys
    return xs




Thanks to @bisserlis for the suggestion to use state

popWhile = state . span