"undefined value, reference not allowed" 解决方法
"undefined value, reference not allowed" workaround
我正在寻找有关编译器错误消息 The value of xyz is undefined here, so reference is not allowed.
以及 do-notation 的说明。我没有设法概括这个例子,我只能给出我偶然发现这种行为的具体例子。对不起。
使用 purescript-parsing,我想编写一个接受嵌套多行注释的解析器。为了简化示例,每个评论都以 (
开头,以 )
结尾,并且可以包含 a
或其他评论。一些示例:(a)
和 ((a))
被接受,()
、(a
或 foo
被拒绝。
以下代码导致第 content <- string "a" <|> comment
行出现错误 The value of comment is undefined here, so reference is not allowed.
:
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 方法是什么?
如果您手动对 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
最好地解决它,我可以想到几个选项,但 none 特别优雅。也许是这样的:
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 ->
可能会更容易,因此您可以延迟递归引用直到 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
我正在寻找有关编译器错误消息 The value of xyz is undefined here, so reference is not allowed.
以及 do-notation 的说明。我没有设法概括这个例子,我只能给出我偶然发现这种行为的具体例子。对不起。
使用 purescript-parsing,我想编写一个接受嵌套多行注释的解析器。为了简化示例,每个评论都以 (
开头,以 )
结尾,并且可以包含 a
或其他评论。一些示例:(a)
和 ((a))
被接受,()
、(a
或 foo
被拒绝。
以下代码导致第 content <- string "a" <|> comment
行出现错误 The value of comment is undefined here, so reference is not allowed.
:
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 方法是什么?
如果您手动对 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
最好地解决它,我可以想到几个选项,但 none 特别优雅。也许是这样的:
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 ->
可能会更容易,因此您可以延迟递归引用直到 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