13

我是 Haskell 的新手。一直困扰我的一件事是,Haskell 是像 Java 这样的托管(从 MS 借用的术语)语言还是像 C 这样的编译为本机代码?

GHC 页面说“GHC 将 Haskell 代码直接编译为本机代码或使用 LLVM 作为后端”。

在“编译为本机代码”的情况下,如果没有 JVM 之类的东西,垃圾收集之类的功能怎么可能实现?

/更新/

非常感谢您的回答。从概念上讲,请您帮忙指出我对 Haskell 中垃圾收集的以下理解中哪一个是正确的:

GHC 将 Haskell 代码编译为本机代码。在编译的过程中,会在原程序代码中加入垃圾回收例程吗?

或者

有一个程序与 Haskell 程序一起运行以执行垃圾收集?

4

5 回答 5

21

据我所知,术语“托管语言”特指以 .NET/公共语言运行时为目标的语言。所以不,Haskell 不是托管语言,Java 也不是。

关于 Haskell 被编译成什么:正如你引用的文档所说,GHC 将 Haskell 编译为本机代码。它可以通过直接发出本机代码或首先发出 LLVM 代码然后让 LLVM 将其编译为本机代码来实现。无论哪种方式,运行 GHC 的最终结果都是本机可执行文件。

除了 GHC 之外,还有其他 Haskell 实现——最著名的是 Hugs,它是一个纯解释器,从不产生可执行文件(本机或其他)。

如果没有 JVM 之类的东西,垃圾收集之类的功能怎么可能实现?

与 JVM 可能的方式相同:每次分配内存时,都会向垃圾收集器注册。然后不时地运行垃圾收集器,按照给定的垃圾收集算法的步骤运行。GHC 编译的代码使用分代垃圾回收。


回应您的编辑:

GHC 将 Haskell 代码编译为本机代码。在编译的过程中,会在原程序代码中加入垃圾回收例程吗?

基本上。除了说“垃圾收集例程将被添加到原始程序代码中”可能会描绘错误的画面。GC 例程只是每个 Haskell 程序链接的库的一部分。编译后的代码只包含在适当位置对这些例程的调用。

基本上每次调用 malloc 时都调用 GC 的 alloc 函数。

只需查看 C 的任何 GC 库及其使用方式:您需要做的就是#include 库的标头并链接到库,并用 GC 库的 alloc 函数替换 malloc 的每个出现(并删除所有调用free)和 bam,你的代码是垃圾收集的。

有一个程序与 Haskell 程序一起运行以执行垃圾收集?

不。

于 2012-05-30T04:09:19.527 回答
13

Haskell 是否是托管(从 MS 借用的术语)语言,如 Java

GHC 编译的程序包括一个垃圾收集器。(据我所知,Haskell 的所有实现都包括垃圾收集,但这不是规范的一部分。)

还是像 C 这样的编译为本机代码?

GHC 编译的程序被编译为本机代码。Hugs 解释程序,并且不编译为本机代码。据我所知,还有其他几种实现都可以编译为本机代码,但我将它们单独列出,因为我对这个事实没有信心。

在“编译为本机代码”的情况下,如果没有 JVM 之类的东西,垃圾收集之类的功能怎么可能实现?

GHC 编译的程序包括一个运行时系统,它提供一些基本功能,如 M 到 N 绿色线程、垃圾收集和 IO 管理器。从某种意义上说,这有点像拥有“类似 JVM 的东西”,因为它提供了许多相同的功能,但在实现上却大不相同:所有架构都没有通用字节码(因此没有“虚拟机”) .

我对 Haskell 中垃圾收集的以下理解之一是正确的:

  1. GHC 将 Haskell 代码编译为本机代码。在编译的过程中,会在原程序代码中加入垃圾回收例程吗?
  2. 有一个程序与 Haskell 程序一起运行以执行垃圾收集?

情况1是正确的:运行时系统代码是在编译过程中添加到程序代码中的。

于 2012-05-30T04:07:04.863 回答
4

“托管语言”是一个超载的术语,所以这里是一个单词的答案,然后是一些关于(我)想到的通常不同含义的细节:

像在 CLR 目标中一样管理

,Haskell 不会编译到 Microsoft CLI 的 IL。
好吧,我读到有一些解决方案可以做到这一点,但是 imo,不要.. CLR 不是为 FP 构建的,并且会严重缺乏优化,可能会产生研究语言性能。如果我个人真的很想以 CLR 为目标,我会使用 F#——它不是一种函数式语言,但它很接近。

注意这是术语“托管语言”的最准确和实际含义。接下来的意思是,好吧,错误的,但不幸的是,很常见。

像自动垃圾收集一样管理

的,这几乎是必须的。我的意思是,超出规范:如果我们必须进行垃圾收集,它将破坏使我们在高海拔地区工作的功能主题,这是我们心爱的家园。

它还将强制执行杂质和内存模型。

管理为编译为由 VM 运行的字节码

没有(通常)
这取决于你的后端:今天不仅我们有不同的 Haskell 编译器,一些编译器也有不同的后端——甚至还有 JavaScript 的后端!

因此,如果您确实想以 VM 为目标,您可以使用现有的/为其创建后端。但是 Haskell不需要它。因此,就像您可以编译为原生原始金属二进制文件一样,您也可以编译为其他任何内容。

与 C# 1、VB.NET 等 CLR 语言相比,与 Java 等相比,您不必针对JVM、CLR、Mono 等,因为 Haskell 根本不需要VM。

GHC 就是一个很好的例子。当您在 GHC 中编译时,它不会将您直接编译为二进制,而是编译为一种称为 Core 的中间语言,然后从 Core 到 Core 优化一段时间,然后再转到另一种称为 STG 的语言,然后才继续编写代码一代(如果你告诉它,它可以停在那里)。2现在,您还可以使用它编译为 LLVM 字节码(经过一些很棒的优化)。借助 LLVM 后端,GHC 可以生成速度快得多的程序。有关它和 GHC 后端的更多信息,请访问此处

下图说明了 GHC 编译管道,您可以在此处找到有关各个阶段的更多信息。

GHC 编译管道

看到三个不同目标底部的叉子了吗?这些是我所指的后端。


1一个未来的例外和一个有趣的事实:微软目前正在开发原生 .NET!巧妙地命名为:Microsoft .NET Native

于 2015-01-22T22:37:12.650 回答
1

对您而言,“托管语言”的定义特征是什么?您引用的短语“GHC 将 Haskell 代码直接编译为本机代码或使用 LLVM 作为后端”非常清楚 GHC 的作用,因此我怀疑困扰您的“歧义”是“托管语言”一词" 比 GHC 的文档中的要好。

在“编译为本机代码”的情况下,如果没有 JVM 之类的东西,垃圾收集之类的功能怎么可能实现?

您认为“像 JVM 之类的东西”究竟是如何实现垃圾收集等功能的?JVM 并不神奇,它只是一个和其他一切一样的程序。在某种程度上,您需要拥有本机代码才能让 CPU 执行它,因此很明显,像垃圾收集这样的功能在本机代码中是可能的。

于 2012-05-30T06:15:46.290 回答
0

对于您目前所处的位置,最好将 (GHC) Haskell 视为“托管”,但GHC 编译到的平台不是其他任何目标。当然,它的意义远不止于此,但这是一个足够的解释,而不是更多的 Haskell 经验。

于 2012-05-30T04:12:51.837 回答