Haskell在编译状态下的可变性?

时间:2010-05-25 17:44:30

标签: compiler-construction haskell

我对Haskell了解不多,但是从我读过的有关计算可变性的内容(例如:函数返回函数,复杂的monad和函数等)看起来你可以做很多元编程,即使在运行时也是如此。

  • 如果函数和monad之类的东西如此复杂,Haskell如何编译成机器代码并保留所有这些?

4 个答案:

答案 0 :(得分:8)

我不确定你的“可变性”是什么意思,但是将这种抽象语言编译成高效的机器代码肯定是一件复杂的事情。作为一个起点,你可以阅读The Implementation of Functional Programming Languages,这是Haskell背后的主要人物Simon Peyton-Jones的一本书。

对于更新的东西,有some commentary on the internals of GHC,旗舰Haskell编译器。

在一个更实际的说明中,如果它只是你想知道的“作为价值观的功能”的想法,那就是旧帽子--Lisp方言一直在编译高阶函数的时间比我长。我们还活着,甚至连C都指向周围的功能。

答案 1 :(得分:8)

  

Haskell如何编译成机器代码......?

通过此编译策略:Implementing Lazy Functional Languages on Stock Hardware

答案 2 :(得分:5)

你以非标准的方式使用“不可变”这个词令人困惑。如果某些数据是不可变的,我们的意思是它不会在程序的整个生命周期中发生变化。我认为你要问的是:Haskell允许你将函数视为第一类对象,这样你就可以动态地构建旧函数。您想知道如果编译器在运行时之前不知道哪些函数会存在,那么如何将其编译为机器代码。这是一个很好的问题。

我将描述可以使用的方法的一部分。不一定是真正的编译器所做的。这只是一个理论上的想法,让您了解如何编译动态显示的功能。 (实际上,我在玩具编译器中使用过它。)

这是一个Haskell函数

f x = let w = 3*x
          g y = w+2*y in g

f就像你描述的那样。它构建了一个名为g的新函数,它将其参数加倍并添加3*x。然后它返回新函数。如果在将x传递到f之前甚至不知道函数是什么,那么如何编译该函数?

编译器可以执行一个名为Lambda lifting的阶段。它看到你在本地创建了一个名为g的函数,并将其作为一个全局函数拉出来。有一个问题。我们无法使g成为全局函数,因为它取决于本地值w。因此,我们将g作为一个全局函数,将w作为参数:

g' w y = w+2*y

现在编译器可以重写f以返回g',为其提供所需的参数:

f' x = let w = 3*x in g' w

您现在可能会问,“如果g'需要2个参数,我们如何才能返回g' x只提供g'一个参数?”。在内部,编译器可以生成所谓的closure。它将g' w表示为包含一对对象,全局函数g'的指针(或其他)和值w的结构。编译器现在可以继续编译g'作为普通函数。我希望你看到我们已经消除了可以构建新功能的任何地方。每当我们将g' w应用于第二个参数时,编译器都可以发现它已经存储了第一个参数,并将其和第二个参数传递给g'

同样,我会强调有很多方法可以编译功能代码,我刚才描述了一件你可以做的事情。但只是展示一种方式应该带走一些关于它可能的事实的神秘感。真正的编译器可能会以各种方式优化您的代码,甚至无需构建闭包。我认为最新的C ++标准可能正如我所描述的那样实现新的lambda

我想我明白你的来源。当我开始学习Haskell时,我非常关注“如何编译汇编语言?”人。因此,在我最初理解Haskell之后,我只是停下来,编写了我自己的基于this论文的函数式语言编译器,然后以更深入的理解返回Haskell。 SASL根本不像Haskell那样编译,但它足以让我更容易理解Haskell 是如何编译的。

答案 3 :(得分:1)

Haskell实际上是强不可变的并且非常静态。您可以获得动态行为和可变性,但默认值是不可变数据结构和严格的引用透明性。