我正在寻找有关编译器错误消息The value of xyz is undefined here, so reference is not allowed.
的一些说明以及标记。我没有设法足够概括这个例子,我能给出的只是具体的例子,我偶然发现了这种行为。对不起。
使用purescript-parsing,我想编写一个接受嵌套多行注释的解析器。为简化示例,每条评论都以(
开头,以)
结尾,可以包含a
或其他评论。一些示例:(a)
和((a))
已被接受,()
,(a
或foo
被拒绝。
以下代码导致行The value of comment is undefined here, so reference is not allowed.
上的错误content <- string "a" <|> comment
:
comment :: Parser String String
comment = do
open <- string "("
content <- commentContent
close <- string ")"
return $ open ++ content ++ close
commentContent :: Parser String String
commentContent = do
content <- string "a" <|> comment
return content
我可以通过在content <- string "a" <|> comment
上方插入一行来消除错误,据我所知,它根本不会改变生成的解析器:
commentContent :: Parser String String
commentContent = do
optional (fail "")
content <- string "a" <|> comment
return content
问题是:
答案 0 :(得分:4)
如果您手动去除do
:
commentContent :: Parser String String
commentContent =
optional (fail "") >>= \_ ->
string "a" <|> comment >>= \content ->
return content
以这种方式定义时,comment
引用位于lambda内部,因此在commentContent
的定义期间不会对其进行求值。
对于非hacky解决方案,它会涉及fix
我想象的一些用法。 fix
允许您定义递归解析器,如:
myParser = fix \p -> do
... parser definition ....
其中p
是对myParser
的引用,您可以在其中使用。至于你有相互递归解析器的情况,我不确定如何用fix
最好地解决它,我可以想到几个选项,但没有一个特别优雅。也许是这样的:
parens :: Parser String String -> Parser String String
parens p = do
open <- string "("
content <- p
close <- string ")"
return $ open ++ content ++ close
comment :: Parser String String
comment = parens commentContent
commentContent :: Parser String String
commentContent = fix \p -> do
content <- string "a" <|> parens p
return content
使用类似于奇怪的do
情况的技巧并在其中一个解析器前插入Unit ->
可能更容易,因此您可以延迟递归引用直到{{1}提供了值,如:
Unit