First use MonadPlus instead of [] in the parser. This will make it more general and simplify the code a bit (we won't have as many nested [] s):
newtype Parser amb = P { runP :: [a] -> m (b, [a]) }
I suggest you change the signature of your routines. You need:
- if the routine requires more input or not, and
- save a fortune somewhere.
This can be easily done with this type signature:
newtype Sub ab = Sub { runSub :: Either (a -> Sub ab) [b] }
A subroutine either produces a result or requests a new input, but also creates a new subroutine. That way, you can save any state you need by passing it to the returned routine. Then the conversion function will look like this:
withf :: (MonadPlus m) => Sub ab -> Parser amb withf start = P $ f (runSub start) where f (Right bs) xs = msum [ return (b, xs) | b <- bs ] f (Left r) [] = mzero -- No more input, can't proceed. f (Left r) (x:xs) = f (runSub (rx)) xs
Update: Another approach we could take is to understand that the parser is actually a StateT transformer whose state is [a] :
type Parser amb = StateT [a] mb runP :: (Monad m) => Parser amb -> [a] -> m (b, [a]) runP = runStateT
Indeed, runP exactly runStateT !
Thus, we get a copy of Monad for Parser for free. And now we can divide our task into smaller blocks. First, we create a parser that consumes a single input or does not work:
receive :: (MonadPlus m) => Parser ama receive = get >>= f where f [] = mzero -- No more input, can't proceed. f (x:xs) = put xs >> return x
and then use it to describe withf :
withf :: (MonadPlus m) => Sub ab -> Parser amb withf start = f (runSub start) where f (Right bs) = msum (map return bs) f (Left r) = receive >>= f . runSub . r
Note that if m is MonadPlus , then StateT sm is also MonadPlus , so we can use mzero and msum with Parser .