【问题标题】:How are Haskell programs compiled and executed internally?Haskell 程序是如何在内部编译和执行的?
【发布时间】:2012-09-07 01:18:19
【问题描述】:

我无法理解 Haskell (GHC) 如何编译程序,以及这些程序是如何运行的。

  1. GHC 是用 Haskell 编写的非平凡程序的典型示例。但是,GHC 的某些部分似乎不是用 Haskell 编写的,即运行时环境(C/C--)。这是为什么?性能原因? (我知道this site 和它的朋友们,但不太了解他们。)
  2. 谈到运行时环境:为什么编译语言需要一个?编译的程序不应该是机器代码而没有别的吗?据我了解,运行时环境有点类似于虚拟机或字节码解释器,它处理某种形式的元代码并在此基础上进行实际计算。那么:GHC 运行时到底做了什么,为什么首先需要它?
  3. 关于 FFI:如何处理 C 调用?最初,我认为使用 FFI 会生成一个可执行文件,其中 Haskell 和 C 编译在一起。但是,我多次读到 GHC 程序会从程序中调用 C 函数。这对于理解 FFI 在并行编程方面的问题尤其重要。那么:FFI 函数与普通 Haskell 函数有何不同?

【问题讨论】:

  • 说到C,就算是用a runtime environment,也往往不是C本身写的。
  • “那么:GHC 运行时到底做了什么,为什么首先需要它?”例如内存管理和线程调度。
  • @C.A.McCann:您的链接显示runtime library,与runtime environment 不同。 C/C++ runtime library 与 Java 等使用的典型运行时环境完全不同。
  • @David 因为在 haskell 中并没有真正用于处理内存管理的工具,它允许您在上面的抽象层上使用类型值进行编程,而不是低得多的级别。
  • @C.A.McCann:Java 是对“运行时环境”的常用和习惯用法的引用。我认为我写的内容很清楚。

标签: haskell compilation runtime ghc


【解决方案1】:

要在现有硬件上编译和执行编程语言,您需要做很多事情:

  • 将源语言翻译成本机主机可执行的汇编代码的编译器
  • 一个用于原始语言服务的支持库(又名运行时),例如内存管理、IO 和线程管理。必须从较低级别的系统服务中利用的东西。

C、Java 和 GHC Haskell 就是此类系统的示例。对于 GHC,entire architecture is described here。这些作品也被单独详细地描述。

【讨论】:

    【解决方案2】:

    我可以提供一些关于什么是运行时的精确度。

    虚拟机是“一种”运行时,但不是唯一的。运行时系统只是您的程序可以假定在执行期间存在的环境(和一组服务)。即使是 C 和 C++ 等非常低级的语言也有运行时系统(想想 malloc ......某人/某物正在为您分配,甚至除以零检查)。

    一般而言,高级语言具有更丰富的运行时(意味着运行时为执行程序提供更多服务);这些范围从内存管理(例如垃圾收集)到反射/自省基础设施(想想 ruby​​ 等)再到数组边界检查,但几乎所有语言都有某种运行时系统(如果只有操作系统的话)。

    【讨论】:

      【解决方案3】:

      1:为什么 RTS 不是用 Haskell 编写的?

      因为它做了一些在 Haskell 中无法表达的低级工作。就像 Linux 内核是一个运行 C 程序的系统一样,但 Linux 内核的某些部分是用汇编而不是 C 编写的。

      2:为什么编译好的程序需要运行时环境?据我了解,这类似于 Java 字节码解释器。

      GHCi 使用的东西几乎与 Java 字节码解释器一模一样。 编译的 GHC 程序没有;编译后的程序是原始机器码。

      Haskell RTS 更像是一种迷你操作系统。它进行内存管理、线程调度、异常处理的某些方面以及事务处理。每个 Haskell 程序都在这个迷你操作系统下运行。

      (这有点像即使一个 C 程序被编译,它是原始机器代码,但你仍然无法运行它没有像 Windows 或Linux 什么的。)

      例如,每当 Haskell 程序内存不足时,Haskell 程序就会停止运行,而垃圾收集器就会开始运行。垃圾收集器尝试释放一些内存,一旦释放,Haskell 程序就会再次开始运行。

      每个编译的 Haskell 程序都有这个垃圾收集器程序的副本,它只是 Haskell RTS 的一部分。类似地,多个 Haskell 线程可以在一个 OS 线程中运行,因此 RTS 内部有一个线程调度程序。我可以继续...

      3:如何处理 FFI?我以为这些东西都是编译在一起的。

      全部编译[或者更确切地说,链接]在一起。如果你编写一个 C 程序,一个 C 函数可以调用另一个 C 函数。当 Haskell 调用 C 函数时,它与调用该 C 函数的任何其他函数非常相似。根据函数调用的作用,Haskell 端会发生一些事情,这可能会增加一些开销。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-09-25
        • 2023-03-20
        • 2010-10-06
        • 1970-01-01
        • 2023-03-13
        • 1970-01-01
        • 1970-01-01
        • 2022-12-07
        相关资源
        最近更新 更多