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

解析边缘案例Haskell模块导入和导出,haskell,compiler-construction,compilation,Haskell,Compiler Construction,Compilation,我正在编写一个小Haskell编译器,我想实现尽可能多的Haskell 2010。我的编译器可以解析一个模块,但将模块完成到一个程序似乎是一项不平凡的任务。我编写了一些棘手但可能有效的Haskell模块示例: module F(G.x) where import F as G x = 2 这里模块F导出G.x,但是G.x与F.x相同,因此模块F导出x如果且仅当它导出x module A(a) where import B(a) a = 2 module B(a) where

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

module F(G.x) where
  import F as G
  x = 2
这里模块
F
导出
G.x
,但是
G.x
F.x
相同,因此模块
F
导出
x
如果且仅当它导出
x

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

module B(a) where
  import A(a)
在本例中,为了解析模块
A
的导出,编译器必须检查从
B
导入的
A
是否与声明的
A=2
相同,但是
B
导出
A
如果且仅当
A
导出
A

module A(f) where
  import B(f)

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

在这里,
模块
导出导致导出列表相互依赖,也相互依赖

根据Haskell 2010规范的定义,所有这些示例都应该是有效的Haskell

我想问一下,是否知道如何正确、完整地实现Haskell模块

假设模块只包含(简单的)变量绑定,
导入
s(可能带有
as
限定
),并导出可能限定的变量列表和
模块…
缩写。算法必须能够:

  • 计算每个模块导出变量的有限列表
  • 将每个导出变量链接到其绑定
  • 将每个模块中使用的每个(可能是限定的)变量链接到其绑定
您可能会感兴趣

我还将在一系列博客文章中介绍一些有趣的边缘案例,其中只有到目前为止才发表

最后,我正致力于这一点——一个处理Haskell模块的库。它叫

根据您的目标,您可以简单地在编译器中使用它,研究源代码或贡献。(您的示例将成为优秀的测试用例。)


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

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


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

Wow,谢谢,我甚至不希望有针对此问题的论文和库:)
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