我正在寻找有关编译器错误消息The value of xyz is undefined here, so reference is not allowed.以及 do-notation 的一些说明。我没有设法对这个例子进行足够的概括,我所能给出的只是我偶然发现这种行为的具体例子。对不起。
使用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
Run Code Online (Sandbox Code Playgroud)
我可以通过在上面插入一行来消除错误,content <- string "a" <|> comment据我所知,它根本不会改变结果解析器:
commentContent :: Parser String String
commentContent = do
optional (fail "")
content <- string "a" <|> comment
return content
Run Code Online (Sandbox Code Playgroud)
问题是:
如果您do手动脱糖,则第二种情况起作用的原因变得更加明显:
commentContent :: Parser String String
commentContent =
optional (fail "") >>= \_ ->
string "a" <|> comment >>= \content ->
return content
Run Code Online (Sandbox Code Playgroud)
以这种方式定义时,comment引用位于 lambda 内部,因此在commentContent.
至于非hacky解决方案,它会涉及fix我想象的一些用途。fix允许您定义递归解析器,例如:
myParser = fix \p -> do
... parser definition ....
Run Code Online (Sandbox Code Playgroud)
哪里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
Run Code Online (Sandbox Code Playgroud)
使用类似于奇怪do情况的技巧并Unit ->在其中一个解析器前面插入 a可能更容易,因此您可以延迟递归引用,直到Unit提供该值,例如:
comment :: Parser String String
comment = do
open <- string "("
content <- commentContent unit
close <- string ")"
return $ open ++ content ++ close
commentContent :: Unit -> Parser String String
commentContent _ = do
content <- string "a" <|> comment
return content
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
351 次 |
| 最近记录: |