解决边缘案例Haskell模块的导入和导出

时间:2012-12-30 10:24:38

标签: haskell compiler-construction compilation

我正在编写一个小Haskell编译器,我想尽可能多地实现Haskell 2010。我的编译器可以解析模块,但是将模块完成到程序似乎是一项非常重要的任务。我编写了一些棘手但可能有效的Haskell模块的例子:

module F(G.x) where
  import F as G
  x = 2

此处模块F导出G.x,但G.xF.x相同,因此模块F会导出x if和只有,它导出x

module A(a) where
  import B(a)
  a = 2

module B(a) where
  import A(a)

在此示例中,要解析模块A的导出,编译器必须检查从a导入的B是否与声明的a = 2相同,但是{当且仅当B导出a时,{1}}才会导出A

a

在解析模块module A(f) where import B(f) module B(f) where import A(f) 期间,编译器可能认为从A导入的f存在,这意味着B导出A,因此{{ 1}}可以导入f并导出B。唯一的问题是在任何地方都没有定义A(f)。)。

f

此处,f导出导致导出列表彼此依赖并依赖于它们。

所有这些示例都应该是有效的Haskell,正如Haskell 2010规范所定义的那样。

我想问一下是否有任何想法如何正确和完整地实现Haskell模块?

假设一个模块只包含(简单)变量绑定,module A(module X) where import A as X import B as X import C as X a = 2 module B(module C, C.b) where import C b = 3 module C(module C) import B as C c = 4 s(可能带有moduleimport),并导出可能合格的变量列表和as缩写。算法必须能够:

  • 计算每个模块的导出变量的有限列表
  • 将每个导出的变量链接到其绑定
  • 将每个模块中使用的每个(可能合格的)变量链接到其绑定

1 个答案:

答案 0 :(得分:9)

您可能对A Formal Specification for the Haskell 98 Module System感兴趣。

我还在一系列博客文章中介绍了一些有趣的边缘案例,截至目前只发布了first one

最后,我正在努力 - 一个处理Haskell模块的库。它被称为haskell-names

根据您的目标,您可以在编译器中使用它,研究源代码或贡献。 (您的示例将提供出色的测试用例。)


回答你的问题:通过计算一个固定点来处理递归模块。

您从模块图中的强连接组件开始。对于此组件中的每个模块,首先假设它不导出任何内容。然后,您将重新访问这些模块,并根据新信息计算新的导出列表。您可以证明此过程是单调的 - 每次导出列表增长(或者至少不缩小)。它迟早会停止增长 - 然后你已经达到了固定点。

您可以通过借用静态分析中的一些想法(该社区非常擅长计算固定点)来优化此算法,但我的包目前实现了朴素算法(code)。