我记得有一次读到至少有两种其他替代品与 WAM 大致同时发明。任何指针?
3 回答
在 WAM 之前,有 Clocksin 的 ZIP。它的设计还是很有趣的。SWI-Prolog 使用它。B-Prolog 也慢慢地从 WAM 设计迁移到 ZIP。当然,在这种方式下,许多新的创新被开发出来。另一种选择是 VAM。
截至 1993 年的比较是:
http://www.complang.tuwien.ac.at/ulrich/papers/PDF/binwam-nov93.pdf
与此同时,最有趣的架构发展与 B-Prolog 有关。
WAM 与 ZIP
WAM 和 ZIP 之间的主要区别在于谓词参数的精确接口。在 WAM 中,参数都是通过寄存器传递的,也就是说,要么是真实的寄存器,要么至少是内存中的固定位置。ZIP 通过堆栈传递所有参数。
让我们考虑一个最小的例子:
p(R1,R2,R3,L1,L2,L3) :- % WAM % ZIP
% store L1..L3 % nothing
% nothing % push R1..R3
% init X1..X3 % push X1..X3
q(R1,R2,R3,X1,X2,X3),
% put unsafe X1..X3 % push X1..X3
% load L1..L3 % push L1..L3
r(X1,X2,X3,L1,L2,L3).
打电话之前q
:
WAM 不需要对在相同位置 ( R1..R3
) 传递给第一个目标的参数执行任何操作。这对于二元从句特别有趣——也就是说,最后只有一个常规目标的子句。WAM 在这方面表现出色。
其他参数L1..L3
需要存储在本地。所以对于这些论点,寄存器接口没有做任何好事。
另一方面,ZIP 不需要保存参数 - 它们已经保存在堆栈中。这不仅适用于具有多个目标的子句,而且适用于其他中断目标,如约束或中断。
不利的一面是,ZIP 必须再次推送R1..R3
。
两者都必须初始化X1..X3
并将它们存储在堆栈中。
来电q
:
调用q
时,WAM 必须为 6 个单元分配堆栈空间,X1..X3
而L1..L3
ZIP 需要R1..R3,L1..L3,X1..X3
. 所以在这里,WAM 更节省空间。此外,WAM 允许环境修整(对于更复杂的情况),这对于 ZIP 来说几乎是不可能的。
打电话之前r
:
这r
是最后一次调用,如果没有选择点,系统会尝试为该子句释放空间。
对于 WAM,X1..X3
必须检查存在变量是否仍然是未实例化的局部变量 ( put_unsafe
),如果将它们移到堆上 - 这很昂贵,但很少发生。L1..L3
刚刚加载。就是这样,WAM 现在可以安全地释放本地帧。所以最后调用优化非常便宜。
对于 ZIP,一切都必须照常推送。只有这样,额外的扫描才能检查堆栈上的所有值并相应地移动它们。那是相当昂贵的。一些优化是可能的,但它仍然比 WAM 所做的要多得多。((一个可能的改进是以相反的顺序推送参数。然后变量L1..L3
可能会留在它们的位置。所以这些变量不需要任何处理。我还没有看到这样的实现。))
在题为“抽象 Prolog 指令集”的技术说明中,Warren 还引用了 Bowen、Byrd 和 Clocksin 的另一个编译器。但是,他说这两种架构有很多共同点,所以我不知道该编译器是否真的可以被视为替代方案。
不确定这是否是您的意思,但前两个 Prolog 实现是 Colmerauer 等人用 Fortran 编写的解释器。和 Warren 等人的 DEC PDP-10 本机编译器。
Warren 在 Ait-Kaci 的WAM重建教程的前言中提到了这些。如果这不是您的意思,您可以在该文档或其参考资料中找到它。