【问题标题】:Approaches For Deeply Extending a Parser Library深度扩展解析器库的方法
【发布时间】:2014-02-07 14:27:05
【问题描述】:

我找到的关于解析器组合器的材料涵盖了通过组合构建复杂的解析器,但我想知道是否有任何好的方法可以通过调整库的组合解析器而不完全复制原始库的逻辑来定义解析器。

例如,这是Real world Haskell中定义的简化CSV解析器

import Text.ParserCombinators.Parsec

csvFile = endBy line eol
line = sepBy cell (char ',')
cell = many (noneOf ",\n")
eol = char '\n'

假设csvFile 是在一个库中定义的,那么另一个库是否可以使用自定义版本的cell 解析器创建自己的CSV 解析器,而不必重写linecsvFile 解析器?可以重写源库以使这成为可能吗?这对于 CSV 解析器来说足够简单,但我对广泛适用的解决方案感兴趣。

【问题讨论】:

    标签: parsing haskell functional-programming parser-combinators


    【解决方案1】:

    通常,您需要对要替换的组件的签名进行抽象。例如,在 CSV 示例中,我们需要扩展 csvFile 的类型,以允许我们插入自定义的 cell

    line cell = sepBy cell (char ',')
    csvFile cell = endBy (line cell) eol
    

    显然,这很快就会变得笨拙。然而,我们可以将所有需要的扩展点打包到一个字典中并传递它

    data LanguageDefinition =
      LanguageDefinition { cell :: Parser Cell 
                         , ...
                         }
    

    然后我们在这个LanguageDefinition上参数化整个解析器组合库

    data Parsers = Parsers { line :: Parser Line, csvFile :: Parser [Line], ... }
    
    mkParsers :: LanguageDefinition -> Parsers
    

    这正是 Parsec 的通用 Token 解析模块所采用的方法:参见 Text.Parsec.TokenText.Parsec.Language


    可以采用更通用的方法,将越来越多的内容抽象到正在传递的字典中。这实际上变成了一种面向对象或 OCaml 模块的代码组织方法,并且非常有效。

    民间表达问题指出,在引入更多功能和引入更多变体之间存在矛盾。在这种情况下,您需要一个新的变体,因此您需要修复该功能(并将其全部列在字典中)。这将为引入新变体开辟道路。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-06
      • 1970-01-01
      相关资源
      最近更新 更多