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

pil*_*unk 2 compiler-construction haskell

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

  • 如果像函数和monad这样的东西如此复杂,Haskell怎么能编译成机器代码并保留所有这些?

C. *_*ann 8

我不确定你的"可变性"是什么意思,但是将这种抽象语言编译成高效的机器代码肯定是一件复杂的事情.作为起点,您可以阅读"函数式编程语言的实现",这是Haskell背后的主要人物之一Simon Peyton-Jones的一本书.

对于最新的内容,有一些关于GHC内部的评论,即Haskell旗舰编译器.

在一个更实际的说明,如果它只是你想知道的"作为价值的功能"的想法,这是旧帽子 - Lisp方言编译高阶函数比我活着更久,甚至C传递指向函数的指针.


Don*_*art 8

Haskell怎么能编译成机器代码......?

通过此编译策略:在库存硬件上实现惰性功能语言


sig*_*fpe 5

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

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

这是一个Haskell函数

f x = let w = 3*x
          g y = w+2*y in g
Run Code Online (Sandbox Code Playgroud)

f就像你描述的那样.它构建了一个新的函数g,它将其参数加倍并添加3*x.然后它返回新函数.如何可以在函数编译时,你甚至不知道的功能是什么,直到x被传递到f

编译器可以执行一个名为Lambda lift的阶段.它看到你在本地创建一个被调用的函数g,并将其作为一个全局函数拉出来.有一个问题.我们不能创建g一个全局函数,因为它取决于本地值w.因此,我们将其g作为一个全局函数来进行w论证:

g' w y = w+2*y
Run Code Online (Sandbox Code Playgroud)

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

f' x = let w = 3*x in g' w
Run Code Online (Sandbox Code Playgroud)

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

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

我想我明白你来自哪里.当我开始学习Haskell时,我非常关注"如何编译汇编语言?" 人.所以我一开始就卡住理解哈斯克尔我干脆停止后,写我自己的编译器根据函数式语言这个文件,然后返回一个更加深入的理解哈斯克尔.SASL根本不像Haskell那样编译,但它足以让我更容易理解Haskell 编译方式.