键入问题用Parsec链接CaseOf语句

时间:2012-09-09 04:43:51

标签: haskell types parsec

我正在学习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

谢谢!

2 个答案:

答案 0 :(得分:1)

您的案件中不需要return。在LeftRight中包装内容后,它会在Either中;由于您只需要Either ParseError FieldLeftRight不需要额外的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