为 JSON 字符串编写解析器

Writing Parser for JSON String

作为尝试编写 JSON 解析器的一部分,我正在解析 JSON 字符串值。

根据 Brent Yorgey 教授 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) }

我 运行 遇到了麻烦,因为据我所知,我的第二个解析器 zeroOrMore notEndOfString 简单地消耗了每个 token 直到到达结束字符串。

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)

使用这种应用方法,请给我一个修改上面 parseStringJValue 以实际工作的提示。

注意 - 我对如何使用 Monad 解决它有一个模糊的想法,但我不确定是否需要它们。

notEndOfString 正在匹配和消耗文本 中的任何字符,包括 " 直到结束,所以它会贪婪地消耗所有字符而不是手转到 char '"' 解析器。您需要匹配引号内 不是引号 的任何字符,这意味着您需要 char.

的否定

如果你有 char 那么大概你是从 satisfy 构建它的,这意味着你也可以定义 notChar:

notChar c = satisfy (/= c)

(注意,顺便说一下,notEndOfString 就是 satisfy id)。否则,你可以写成类似 char.

然后您可以通过构建一些其他有用的组合器来定义字符串解析器:

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

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

请注意,这不会处理引号内的转义 ("\"")。


编辑:要强制执行上面隐含的不变量,最好定义

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

然后parseStringJValue = S <$> inside '"' '"'.