Sifu
Sifu

Reputation: 163

Making a monad succeed with failure in haskell

I have a parser monad that looks like this:

data Parser b a = P(b -> [(a, b)])
instance Monad (Parser p) where
  p >>= f = P $ \inp -> case parse p inp of
                           [] -> []
                           [(v, inp')] -> parse (f v) inp'

I also have the following functions/parsers for getting and setting the state of the parser:

getState :: Parser b b
getState = P(\inp -> [(inp, inp)])

setState b -> Parser b ()
setState s = P(\inp -> [(), s)]

Additionally, I have a Parser function that looks ahead to see if there is more to parse without consuming anything:

lookahead :: Parser b a -> Parser b ()
lookahead p = do
                state <- getState
                result <- p
                setState state
                return result

Now, suppose I want to write a Parser function that succeeds if another parser fails: It should fail if there are more to consume and succeed if there isn't.

notFollowedBy :: Parser b a -> Parser b ()
notFollowedBy p = do --statements

The intended usage is to disallow illegal parsers to continue, according to some grammar.

This has me kind of stumped: To my (limited) understanding of Monads, they provide you with a safety net in case any of the evaluations fails. Is there a (good and recommended) way to make this function do the opposite?

Upvotes: 0

Views: 285

Answers (1)

melpomene
melpomene

Reputation: 85907

Here's how you could implement notFollowedBy in your parser:

notFollowedBy :: Parser b a -> Parser b ()
notFollowedBy p = P (\inp -> case parse p inp of
                                [] -> [((), inp)]
                                _  -> [])

This definition relies on being able to access the internals of Parser (specifically the P constructor).

Alternatively you can do the following:

notFollowedBy p = do
    inp <- getState
    case parse p inp of
        [] -> return ()
        _  -> fail "sub-parse succeeded"

Upvotes: 2

Related Questions