Design: 支持 Prolog 和 Haskell

创建于 2015-11-30  ·  9评论  ·  资料来源: WebAssembly/design

https://github.com/WebAssembly/design/issues/483 中的讨论中分离:

我希望看到将这些用例映射到现有模型的一些努力,然后评估哪些仍然无法解决或哪些仍然低效。 多个返回站点的用例可能与支持catch操作或异常处理有关,但不确定。

在 2015/11/30 下午 01:45,Frank McCabe 写道:

Prolog 和 Haskell 都对当前的设计提出了挑战。 在一些
他们也有一个共同的要求:非标准评估
导致需要对评估的表示进行更多控制。

在 Prolog 的情况下,它有一个评估“堆栈”(需要引号)
具有两个在普通语言中没有的特征:非本地返回
(当 Prolog 程序结束时,它的返回不一定在
堆。 但是,仍必须保留该堆栈以支持
回溯。

第二个特点是回溯。 /that/ 的意思是有
程序返回的两种不同方式:成功或
不成功。

编译为机器代码的 prolog 是否保留了单独的绑定堆栈? 除了控制传输之外,使用单独的堆栈能走多远? 甚至翻译的 C 也应该有一个单独的堆栈,用于传递超出固定参数的参数。

一般来说,一个好的 Prolog 实现需要更明确的
比 Java/C++ 语言更能控制其评估堆栈。

Haskell 又是一个不同的案例。 它的实现有很多
对传统语言来说非常陌生的特性。 在第一
在这种情况下,在进入函数之前不会评估参数。 这
这样做的效果是 /all/ 数据看起来像代码。 这也意味着
评估堆栈的普通数组映射对于
哈斯克尔。

这听起来像是一个更高级别的问题。 无论如何,机器代码不支持这一点,因此肯定会将其转换为更原始的操作。 例如,参数可能是指向数据结构的指针,也许这些需要包含一个函数和上下文的索引?

在第二种情况下,一个函数调用可以有多个返回点:
结果表示为单个值的一种,一种或多种
其中返回结果与返回的组件“推迟”
值分布在多个寄存器中。

这是否可以由单个返回站点使用多个值(将被支持)来处理。 第一个值可能是要分派到不同返回路径范围的索引?

...

补充说明:支持 Haskell 所需的结构类型
和 Prolog 也很好地支持所谓的异步
编程。 因此,即使 JavaScript 和 C++ 也可以从这些中受益
技术。

但无论如何它们都被编译为机器码,而机器码并没有对“异步编程”的特定支持。 我们需要知道的是 AST 是否可以有效地支持所需的原始操作。

最有用的评论

我很惊讶Core没有提到 Haskell。

另一个目标

我们的目标不应该是将 _Haskell_ 编译为 WebAssembly,而是将 _Core_ 编译为 WebAssembly。 Haskell 编译器 GHC已经将 Haskell 编译为 Core,它更小、更易于使用但仍可移植。 Haskell 已经通过 Core 编译为程序集(使用 GHC)和JVM 字节码,所以我不明白为什么我们不能为 WebAssembly 做类似的事情。

GHC 做更多的工作

我们甚至可以更进一步,在编译后期拦截 GHC。 例如,GHC 已经将 Core 编译为稍微简单的Spineless Tagless G-machine 。 然后它将 STG 代码转换为 C-- 的方言,此时甚至函数调用都被剥离了。 有关整体解释,请参阅维基百科的GHC § 架构

只要让它成为可能

当然,WebAssembly 团队只需要考虑 Haskell 编译系统的设计即可。 其他人可以编写编译器; 我们只需要确保 WebAssembly 是此类编译器的合适目标,同时保持相对较小和高效。 考虑到 GHC 已经做了多少工作来将 Haskell 编译为低级语言,很可能已经是这样了。

所有9条评论

支持序言

  1. 一个函数可以多次“返回”。 这有点像scheme中的call/cc; 但是目前对函数作为评估单位的固定被这个打破了。 为了支持这一点,Prolog 堆栈比大多数语言中的评估堆栈要丰富得多。 请注意,与 call/cc 不同,Prolog 中的延续是不可具体化的。
  2. Prolog 非常需要变量-变量解引用。 内存引用可能没有实际值,而是指向实际值的指针。 在某些系统中,这占 Prolog 应用程序中所有 CPU 周期的 30-40%。
  3. 普通的基于半空间的 GC 算法不适用于 Prolog,因为有效的回溯依赖于知道分配的顺序。

在 Prolog 中,垃圾收集器也收集堆栈是正常的。 Prolog 中的 cut 运算符导致垃圾堆栈条目。

支持 Haskell
注意:我不是这方面的专家。

  1. 多个返回点可以通过返回一个哨兵和分支来近似; 但要付出巨大的性能代价。 这样的系统不能声称自己支持 Haskell。
  2. 尾递归。 不应该要求尾调用假设尾调用具有与父调用相同数量的参数等。 在函数式语言的许多情况下,它看起来不一样。
  3. 非线性评估堆栈。 Haskell 的普通惰性求值模式使得在堆栈上实现非常困难。 据我所知,Haskell 编译器尝试将求值映射到堆栈,但通常会失败并以堆分配堆栈结束。

在2015年11月29日,在下午8时46分,弗兰克·麦凯布[email protected]写道:

支持序言

一个函数可以多次“返回”。 这有点像scheme中的call/cc; 但是目前对函数作为评估单位的固定被这个打破了。 为了支持这一点,Prolog 堆栈比大多数语言中的评估堆栈要丰富得多。 请注意,与 call/cc 不同,Prolog 中的延续是不可具体化的。
您需要的低级功能是什么? 它是多个函数入口点吗?

请注意,没有什么能阻止 web 上的 prolog 实现堆分配类似堆栈的数据结构并将其用作高级堆栈。 如果 prolog 实现在生成 C 代码时这样做了,那么就整体基准性能而言,它会比以机器代码为目标并做一些更聪明的事情的实现差多少?

Prolog 非常需要变量-变量解引用。 内存引用可能没有实际值,而是指向实际值的指针。 在某些系统中,这占 Prolog 应用程序中所有 CPU 周期的 30-40%。
如果您使用 C 表达它,所需的机器代码与 C 编译器生成的机器代码有何不同?
普通的基于半空间的 GC 算法不适用于 Prolog,因为有效的回溯依赖于知道分配的顺序。

在 Prolog 中,垃圾收集器也收集堆栈是正常的。 Prolog 中的 cut 运算符导致垃圾堆栈条目。

wasm 的任何 GC 功能都需要与 Web 的 GC 语义兼容。 目前尚不清楚您描述的内容是否兼容。

没有什么可以阻止使用线性内存的自定义 GC 实现。

支持 Haskell
注意:我不是这方面的专家。

多个返回点可以通过返回一个哨兵和分支来近似; 但要付出巨大的性能代价。 这样的系统不能声称自己支持 Haskell。
尾递归。 不应该要求尾调用假设尾调用具有与父调用相同数量的参数等。 在函数式语言的许多情况下,它看起来不一样。
非线性评估堆栈。 Haskell 的普通惰性求值模式使得在堆栈上实现非常困难。 据我所知,Haskell 编译器尝试将求值映射到堆栈,但通常会失败并以堆分配堆栈结束。

直接回复此邮件或在 GitHub 上查看。

您需要的低级功能是什么? 它是多个函数入口点吗?

Prolog 程序根本不对应于常规函数。 Prolog 程序的退出不能像正常的函数返回那样处理; 并且相应的调用比常规函数调用有更多的作用。

将其映射到 C 会导致非常庞大的代码,或者更有可能是额外的解释层。 大多数体面的 Prolog 系统都不能编译为 C。

在某些系统中,这占 Prolog 应用程序中所有 CPU 周期的 30-40%。

如果您使用 C 表达它,所需的机器代码与 C 编译器生成的机器代码有何不同?

这里的关键是你会得到看起来像验证器类型违规的东西。 指向值的指针可以是指向值的指针的指针,也可以是指向指向值的指针的指针; 或者它可能只是一个值。

通过 C 编译不可避免地会导致大量的性能损失。

你说的几个地方可以分配一块线性内存并使用它。 这是真实的。 但是您不能同时将其用作首选策略并声称具有普遍性。

一个极端的例子可以说明:您可以将所有 C 程序映射到 Haskell。 然后人们可以声称,给定一个高效的 Haskell 实现,你也有一个高效的 C 实现并且你具有普遍性。 我怀疑很多人会接受这一点。

另一方面,不需要支持 Prolog 或 Haskell。 在这种情况下,不要声称具有普遍性。

其他一些也具有非标准执行模型的语言包括 SQL、Scheme、Ruby 等。

没有什么可以阻止使用线性内存的自定义 GC 实现。

只是想指出,我认为这会很普遍。 有太多不同的 GC 模型,没有一个 VM 可以支持所有这些模型(另一个例子是需要 GC 终结器的语言,而 JS 缺乏),这很好。 其他的可以在线性内存(+ 线程)之上实现,接近本机速度。

你说的几个地方可以分配一块线性内存并使用它。 这是真实的。 但是您不能同时将其用作首选策略并声称具有普遍性。

我不认为我们在这个意义上声称具有很强的普遍性。 它从未实现过,而且很可能是不可能的。

WebAssembly 的主要目标是充当 JavaScript 的汇编程序吗? 我认为我们已经有了广泛的 JS 实现。

我还认为最初的目标是能够编译任意 C 程序以在浏览器中分发。

我想我稍微提高了赌注。 我认为有 _is_ 通用汇编器的潜力。

WebAssembly 的目标在此处详细说明。 最初的重点 (MVP) 确实是在 C/C++ 上,但它也非常打算在此之外“提高赌注”并增加对许多其他类型语言的支持。

FutureFeatures.md文档列出了一些可能的想法(包括完全通用的尾调用),其他想法也是可能的。 这并不意味着是一个全面的清单; 欢迎新想法。

对于 Haskell 来说,一个很好的探索起点可能是 GHC LLVM 后端。 它依赖于LLVM的哪些特殊功能? 它的弱点是什么?

结束,因为没有确定足够具体的内容,如果确定,那么打开新的特定问题似乎更合适。

我很惊讶Core没有提到 Haskell。

另一个目标

我们的目标不应该是将 _Haskell_ 编译为 WebAssembly,而是将 _Core_ 编译为 WebAssembly。 Haskell 编译器 GHC已经将 Haskell 编译为 Core,它更小、更易于使用但仍可移植。 Haskell 已经通过 Core 编译为程序集(使用 GHC)和JVM 字节码,所以我不明白为什么我们不能为 WebAssembly 做类似的事情。

GHC 做更多的工作

我们甚至可以更进一步,在编译后期拦截 GHC。 例如,GHC 已经将 Core 编译为稍微简单的Spineless Tagless G-machine 。 然后它将 STG 代码转换为 C-- 的方言,此时甚至函数调用都被剥离了。 有关整体解释,请参阅维基百科的GHC § 架构

只要让它成为可能

当然,WebAssembly 团队只需要考虑 Haskell 编译系统的设计即可。 其他人可以编写编译器; 我们只需要确保 WebAssembly 是此类编译器的合适目标,同时保持相对较小和高效。 考虑到 GHC 已经做了多少工作来将 Haskell 编译为低级语言,很可能已经是这样了。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

mfateev picture mfateev  ·  5评论

JimmyVV picture JimmyVV  ·  4评论

thysultan picture thysultan  ·  4评论

spidoche picture spidoche  ·  4评论

cretz picture cretz  ·  5评论