Haskell 秒差距 <|> 的问题操作员
我对 Haskell 和 Parsec 都是新手。为了更多地了解该语言,特别是该库,我正在尝试创建一个可以解析 Lua 保存的变量文件的解析器。在这些文件中,变量可以采用以下形式:
varname = value
varname = {value, value,...}
varname = {{value, value},{value,value,...}}
我为每个变量创建了解析器这些类型,但是当我用选择 <|> 将它们串在一起时运算符我收到类型错误。
Couldn't match expected type `[Char]' against inferred type `Char'
Expected type: GenParser Char st [[[Char]]]
Inferred type: GenParser Char st [[Char]]
In the first argument of `try', namely `lList'
In the first argument of `(<|>)', namely `try lList'
我的假设是(尽管我在文档中找不到)传递给选择运算符的每个解析器必须返回相同的类型。 这是有问题的代码:
data Variable = LuaString ([Char], [Char])
| LuaList ([Char], [[Char]])
| NestedLuaList ([Char], [[[Char]]])
deriving (Show)
main:: IO()
main = do
case (parse varName "" "variable = {{1234,\"Josh\"},{123,222}}") of
Left err -> print err
Right xs -> print xs
varName :: GenParser Char st Variable
varName = do{
vName <- (many letter);
eq <- string " = ";
vCon <- try nestList
<|> try lList
<|> varContent;
return (vName, vCon)}
varContent :: GenParser Char st [Char]
varContent = quotedString
<|> many1 letter
<|> many1 digit
quotedString :: GenParser Char st [Char]
quotedString = do{
s1 <- string "\"";
s2 <- varContent;
s3 <- string "\"";
return (s1++s2++s3)}
lList :: GenParser Char st [[Char]]
lList = between (string "{") (string "}") (sepBy varContent (string ","))
nestList :: GenParser Char st [[[Char]]]
nestList = between (string "{") (string "}") (sepBy lList (string ","))
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是正确的。
请注意两个参数的类型完全相同。
我不太明白您的
Variable
数据类型。这就是我这样做的方式:这允许值任意嵌套,而不仅仅是像您的那样嵌套两层。然后写:
这是 luaValue 的解析器。然后你只需要写:
你就会得到它。使用准确表示可能性的数据类型非常重要。
That's correct.
Notice how both arguments are exactly the same type.
I don't exactly understand your
Variable
data type. This is the way I would do it:This allows values to be arbitrarily nested, not just nested two levels deep like yours has. Then write:
This is the parser for luaValue. Then you just need to write:
And you'll have it. Using a data type that accurately represents what is possible is important.
事实上,传递给选择运算符的解析器必须具有相同的类型。您可以通过选择运算符的类型来判断:
这表示只要两个解析器的标记类型、状态类型和结果类型相同,它就会愉快地组合它们。
那么我们如何确保您尝试组合的那些解析器具有相同的结果类型?好吧,你已经有了一个数据类型
Variable
来捕获 Lua 中可能出现的不同形式的变量,所以我们需要做的不是返回String
,[ String]
或[[String]]
但只是Variable
。但当我们尝试这样做时,我们遇到了问题。我们还不能让
nestList
等返回Variable
,因为Variable
的构造函数需要变量名称,而我们还不知道这些变量名称那一点。有一些解决方法(例如返回一个仍需要该变量名称的函数String -> Variable
),但有一个更好的解决方案:将变量名称与变量所包含的不同类型的值分开可以有。请注意,我已删除了
。这允许列表嵌套任意深度,而不是像您的示例中那样只有两层。我不知道 Lua 中是否允许这样做,但它使编写解析器变得更容易。 :-)
NestedLuaList
构造函数。我已将LuaList
更改为接受Value
列表,而不是String
,因此嵌套列表现在可以表示为LuaList
的 >LuaList现在我们可以让
lList
和nestList
返回Value
s:和
varName
,我已将其重命名variable
这里,现在返回一个Variable
:我想你会发现,当你在某些输入上运行解析器时,仍然存在一些问题,但你已经很多了现在比以前更接近解决方案。
我希望这有帮助!
Indeed, parsers passed to the choice operator must have equal types. You can tell by the type of the choice operator:
This says that it will happily combine two parsers as long as their token types, state types and result types are the same.
So how do we make sure those parsers you're trying to combine have the same result type? Well, you already have a datatype
Variable
that captures the different forms of variables that can appear in Lua, so what we need to do is not returnString
,[String]
or[[String]]
but justVariable
s.But when we try that we run into a problem. We can't let
nestList
etc. returnVariable
s yet because the constructors ofVariable
require variable names and we don't know those yet at that point. There are workarounds for this (such as return a functionString -> Variable
that still expects that variable name) but there is a better solution: separate the variable name from the different kinds of values that a variable can have.Note that I've removed the
NestedLuaList
constructor. I've changedLuaList
to accept a list ofValue
s rather thanString
s, so a nested list can now be expressed as aLuaList
ofLuaList
s. This allows lists to be nested arbitrarily deep rather than just two levels as in your example. I don't know if this is allowed in Lua but it made writing the parsers easier. :-)Now we can let
lList
andnestList
returnValue
s:And
varName
, which I've renamedvariable
here, now returns aVariable
:I think you'll find that when you run your parser on some input there are still some problems, but you're already a lot closer to the solution now than before.
I hope this helps!