2012-12-30 51 views
9

我在写一个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的出口,编译器检查aB进口是一样的声明a = 2,但B出口a,当且仅当A出口a

module A(f) where 
    import B(f) 

module B(f) where 
    import A(f) 

在解析模块A,编译器may've假设fB进口存在,这意味着A出口f,从而B可以导入A(f)和出口f。唯一的问题是没有在任何地方定义的f :)。

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 

这里,module出口造成,出口列表是依赖于彼此和自己。

所有这些例子应该是有效的Haskell,由Haskell 2010规范定义。

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

假定一个模块只包含(简单)变量绑定,import S(可能与asqualified),并可能有资格变量的出口列表和module ...缩写。该算法必须能够:

  • 计算每个模块
  • 链接每个导出的变量与其结合
  • 链路每模块中使用与其结合每(也许合格)可变的出口变量的有限列表

回答

9

您可能也有兴趣A Formal Specification for the Haskell 98 Module System

我还介绍了一系列博客文章中的一些有趣的边缘案例,其中只有first one已发布到目前为止。

最后,我正在研究 - 处理Haskell模块的库。它被称为haskell-names

根据您的目标,您可以简单地在编译器中使用它,研究源代码或贡献。 (你的例子会做出很好的测试用例。)


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

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

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

+0

哇,谢谢,我甚至不希望有实际的文件和图书馆针对这个问题:) –