haskell中具有循环依赖性的数据结构

ser*_*eyz 12 haskell cyclic-reference

我正在尝试使用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 = ...
Run Code Online (Sandbox Code Playgroud)

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

那么,有什么方法可以解决这个问题吗?

luq*_*qui 13

我打破依赖循环的典型方法是通过参数化来解决问题.在这种情况下,您的Function模块可能会为您的语言执行函数解析器,但表达方式无论语言的其余部分如何都可以这样做.从而:

module Function where 

data FunctionBody e = FunctionBody [e]

parseFunctionBody :: Parser e -> Parser (FunctionBody e)
Run Code Online (Sandbox Code Playgroud)

module AST where

data SourceElement
    = StatementSourceElement Statement
    | FunctionSourceElement FunctionName (FunctionBody SourceElement)
Run Code Online (Sandbox Code Playgroud)

因此,相互递归被抽象为简单的递归+参数化.我认为参数化至少与将不同的东西分成不同的文件一样重要,所以一方面强迫另一方讨厌(又有点烦人).


Rom*_*aka 6

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

我在这里看到使用此功能没有任何问题.

  • 我认为`.hs-boot`不会给您带来不便。造成不便的原因至少在每次尝试时都使我转向另一种策略。也许这是我的理想主义-我觉得.hs-boot文件应该易于自动生成,因此当我必须自己编写它们时,我会感到沮丧。 (2认同)