3

我正在寻找对编译器错误消息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

我可以通过在上面插入一行来消除错误,content <- string "a" <|> comment据我所知,它根本不会改变生成的解析器:

commentContent :: Parser String String
commentContent = do
  optional (fail "")
  content <- string "a" <|> comment
  return content

问题是:

  • 这里发生了什么?为什么额外的线路有帮助?
  • 什么是让代码编译的非 hacky 方法?
4

1 回答 1

5

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插入 a可能会更容易,因此您可以延迟递归引用直到提供值,例如:Unit ->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
于 2016-05-02T20:35:58.240 回答