0

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

谢谢!

4

2 回答 2

1

你不需要return在你的情况下。一旦你包裹了一些东西Left或者Right它在Either; 既然你只需要一个Either ParseError FieldLeft并且Right不需要一个额外的return

此外,您应该能够parseFields显着简化您的工作。您可以编写一个如下所示的新解析器:

fields = try fieldsWithFlags <|> fieldsWithoutFlags

这样做是运行第一个,如果失败,则回溯并运行第二个。这try很重要,因为这是启用回溯行为的原因。您必须回溯,因为fieldsWithFlags消耗了您关心的一些输入。

现在你应该可以fields在你的main函数中使用了。

于 2012-09-09T05:56:27.440 回答
1

由于没有标志的形式几乎与有标志的形式相同(只是缺少标志),因此可以将替代方案下推到标志可能出现的位置。通过这种方式,您可以避免回溯名称并输入 with-flags,只是为了在 without-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
于 2012-09-09T18:05:14.777 回答