我正在学习haskell,我当前的项目正在编写一个解析器来读取数据库的文本文件表示。
目前,我正在设置读取表格各个字段的代码。在文本文件中,字段看起来像这样:
name type flags format
或者这个:
name type format
这给了必须考虑有旗帜或不是旗帜的情况的麻烦。我在我的主要功能中解决了这个问题:
main = case parse fieldsWithFlags "(test)" testLine of
Left err -> noFlags
Right res -> print res
where noFlags = case parse fieldsWithoutFlags "(test)" testLine of
Left err -> print err
Right res -> print res
如果我理解正确,这说“如果它是没有标志的行,请尝试解析它;否则,返回错误。”它为我抛出的任何“testLine”打印正确的结果,如果两个选项都失败则返回错误。但是,当我尝试将其拉出自己的功能时,如下所示:
field :: Either ParseError Field
field = case parse fieldsWithFlags "(test)" testLine of
Left err -> noFlags
Right res -> return Right res
where noFlags = case parse fieldsWithoutFlags "(test)" testLine of
Left err -> return Left err
Right res -> return Right res
main = case field of
Left err -> print err
Right res -> print res
GHC给了我:
haskellParsing.hs:58:26:
Couldn't match expected type `Either ParseError Field'
with actual type `b0 -> Either b0 b0'
In the expression: noFlags
In a case alternative: Left err -> noFlags
In the expression:
case parse fieldsWithFlags "(test)" testLine of {
Left err -> noFlags
Right res -> return Right res }
我已经玩了很多,但却无法让它发挥作用。我确信有一个更清醒的方式来做这个,所以任何建议都会受到欢迎 - 但我也想知道为什么这不起作用。
完整代码位于:http://pastebin.com/ajG6BkPU
谢谢!
答案 0 :(得分:1)
您的案件中不需要return
。在Left
或Right
中包装内容后,它会在Either
中;由于您只需要Either ParseError Field
,Left
和Right
不需要额外的return
。
此外,您应该能够显着简化parseFields
。您可以编写一个如下所示的新解析器:
fields = try fieldsWithFlags <|> fieldsWithoutFlags
这样做是运行第一个,如果失败,则回溯并运行第二个。 try
很重要,因为这是启用回溯行为的原因。您必须回溯,因为fieldsWithFlags
会消耗您关心的一些输入。
现在,您应该可以在fields
功能中使用main
。
答案 1 :(得分:1)
由于没有标志的表单几乎与带有标志的表单相同(只是缺少标志),因此可以将替代方法下推到标志可能出现的位置。通过这种方式,您可以避免回溯名称并输入with-flags,只需在无标记中再次解析它们。我们可以结合使用和不使用字段解析器,如下所示:
fields = do
iName <- getFieldName
spaces
iType <- getDataType
spaces
iFlag <- option "" $ try getFlag
spaces
iFormat <- getFormat
newline -- this was only present in without flags, was that intended?
return $ Field iName iType iFlag iFormat