我正在尝试使用parsec
库在haskell中实现简单的解析器(用于学习目的)。所以我写了一堆数据结构和相关函数,如下所示:
data SourceElement
= StatementSourceElement Statement
| FunctionSourceElement FunctionName FunctionBody
data Statement
= IfStatement Expr Statement Statement
| WhileStatement Expr Statement
data FunctionBody = FunctionBody [SourceElement]
parseSourceElement :: Parser SourceElement
parseSourceElement = ...
parseFunctionBody :: Parser FunctionBody
parseFunctionBody = ...
工作正常。现在我想将这些内容分成两个模块来分隔FunctionBody
和Statement
数据结构(因为可读性问题)。但我不能!原因是SourceElement
和FunctionBody
之间存在循环依赖关系。
那么,有什么方法可以解决这个问题吗?
答案 0 :(得分:12)
我打破依赖循环的典型方法是通过参数化来解决问题。在这种情况下,您的Function
模块可能会为您的语言执行函数解析器,但无论语言的其余部分是什么,它都可以这样表达。因此:
module Function where
data FunctionBody e = FunctionBody [e]
parseFunctionBody :: Parser e -> Parser (FunctionBody e)
和
module AST where
data SourceElement
= StatementSourceElement Statement
| FunctionSourceElement FunctionName (FunctionBody SourceElement)
因此,相互递归被抽象为简单的递归+参数化。我认为参数化至少与将不同的东西分成不同的文件一样重要,所以一方面强迫另一方是好的(而且有点烦人)。
答案 1 :(得分:5)
Haskell实际上允许递归模块,GHC支持它们(编写.hs-boot
文件时带来轻微不便)。请参阅How to compile mutually recursive modules。
我在这里看到使用此功能没有任何问题。