1

As part of trying to write a JSON Parser, I'm working on parsing a JSON String value.

Given the following definition from Prof. Brent Yorgey's Haskell course:

-- A parser for a value of type a is a function which takes a String
-- represnting the input to be parsed, and succeeds or fails; if it
-- succeeds, it returns the parsed value along with the remainder of
-- the input.
newtype Parser a = Parser { runParser :: String -> Maybe (a, String) }

I'm running into trouble since, as I understand, my second parser, zeroOrMore notEndOfString, simply consumes every token until reaching the end of the String.

data JValue = S String | ...

parseStringJValue :: Parser JValue
parseStringJValue = S <$> ((char '"') *> (zeroOrMore notEndOfString) <* (char '"'))

notEndOfString :: Parser Char
notEndOfString = Parser f
  where 
    f []     = Nothing
    f (x:xs) = Just (x, xs)

Using this applicative approach, please give me a hint towards modifying my above parseStringJValue to actually work.

Note - I have a faint idea on how to solve it with Monads, but I'm not sure if if they are required.

2
  • Hint: the String in notEndOfString is the result of your parse, not the input to be parsed.
    – genisage
    Commented Feb 16, 2015 at 6:49
  • You probably want zeroOrMore notEndOfStringOrQuote. In parsec, for example, I would probably just write many (noneOf "\""). Commented Feb 16, 2015 at 19:47

1 Answer 1

1

notEndOfString is matching and consuming any characters in the text including " until the end, so it acts greedily to consume all characters and never hands off to the char '"' parser. You need to match any characters inside of the quotes that aren't a quote, which means you need the negation of char.

If you have char then presumably you built it from satisfy, which means you can also define notChar:

notChar c = satisfy (/= c)

(Note, by the way, that notEndOfString is just satisfy id). Otherwise, you can write it similarly to char.

Then you can define the parser for strings by building up a few other useful combinators:

bracket l r p = l *> p <* r
quotes = bracket (char '"') (char '"')

parseStringJValue = S <$> quotes (zeroOrMore (notChar '"'))

Note that this won't handle escapes ("\"") within quotes.


Edit: To enforce the invariant that is implicit above, it would be nice to define

inside l r = bracket (char l) (char r) (zeroOrMore (notChar r))

Then parseStringJValue = S <$> inside '"' '"'.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.