我写了一个非常简单的解析器组合库,它似乎正常工作(https://github.com/mukeshsoni/tinyparsec)。
然后我尝试用json为json编写解析器。 json解析器的代码在这里 - https://github.com/mukeshsoni/tinyparsec/blob/master/src/example_parsers/JsonParser.purs
json的语法是递归的 -
data JsonVal
= JsonInt Int
| JsonString String
| JsonBool Boolean
| JsonObj (List (Tuple String JsonVal))
这意味着json对象的解析器必须再次调用jsonVal
的解析器。 jsonObj
解析器的代码如下所示 -
jsonValParser
= jsonIntParser <|> jsonBoolParser <|> jsonStringParser <|> jsonObjParser
propValParser :: Parser (Tuple String JsonVal)
propValParser = do
prop <- stringLitParser
_ <- symb ":"
val <- jsonValParser
pure (Tuple prop val)
listOfPropValParser :: Parser (List (Tuple String JsonVal))
listOfPropValParser = sepBy propValParser (symb ",")
jsonObjParser :: Parser JsonVal
jsonObjParser = do
_ <- symb "{"
propValList <- listOfPropValParser
_ <- symb "}"
pure (JsonObj propValList)
但是当我尝试构建它时,我收到以下错误 - The value of propValParser is undefined here. So this reference is not allowed here
我在stackoverflow上发现了类似的问题但是无法理解错误发生的原因或者我应该如何重构我的代码以便它处理从jsonValParser
到propValParser
的递归引用。
任何帮助都将不胜感激。
答案 0 :(得分:1)
有关类似情况,请参阅https://stackoverflow.com/a/36991223/139614 - 您需要使用fix
函数,或在某个解析器前面引入Unit -> ...
以打破循环定义。< / p>
答案 1 :(得分:0)
我设法通过在do块中包含抛出错误的块并用noop启动do块来摆脱错误 -
listOfPropValParser :: Parser (List (Tuple String JsonVal))
listOfPropValParser = do
_ <- pure 1 -- does nothing but defer the execution of the second line
sepBy propValParser (symb ",")
必须为jsonValParser做同样的事。
jsonValParser = do
_ <- pure 1
jsonIntParser <|> jsonBoolParser <|> jsonStringParser <|> jsonObjParser
这个想法是推迟执行可能导致循环依赖的代码。添加的行_ <- pure 1
就是这样做的。我认为它可能与来自fix
的{{1}}或来自Data.Fix
的{{1}}做同样的事情。