12

我正在尝试使用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 = ...

它工作正常。现在我想把这些东西分成两个模块来分开FunctionBodyStatement数据结构(因为可读性问题)。但我不能!原因是 和 之间的循环SourceElement依赖FunctionBody

那么,有没有办法解决这个问题呢?

4

2 回答 2

13

我打破依赖循环的典型方法是参数化一些东西。在这种情况下,您的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)

因此相互递归被抽象为简单的递归+参数化。我认为参数化至少与将不同的东西分成不同的文件一样重要,所以一个强迫另一个是很好的(也有点烦人)。

于 2012-12-09T15:20:22.493 回答
6

.hs-bootHaskell 实际上允许递归模块,而 GHC 支持它们(写入文件有一点不便)。请参阅如何编译相互递归的模块

我认为在这里使用此功能没有任何问题。

于 2012-12-09T16:39:35.703 回答