我记得曾经读过,与WAM大致同时发明了至少两个其他替代方案。有指针吗?

最佳答案

在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之前:

对于在相同位置(R1..R3)传递给第一个目标的参数,WAM不需要执行任何操作。对于二进制子句来说,这尤其有趣-即,结尾恰好有一个常规目标的子句。 WAM在这里表现出色。

其他参数L1..L3需要存储在本地。因此,对于这些参数,寄存器接口没有任何好处。

另一方面,ZIP不需要保存参数-它们已经保存在堆栈中。这不仅对具有多个目标的子句有益,而且对其他中断目标(如约束或中断)也有好处。

不利的一面是,ZIP必须再次按下R1..R3

两者都必须初始化X1..X3并将它们存储在堆栈中。

呼叫q

调用q时,WAM必须为X1..X3L1..L3分配堆栈空间,因此需要分配6个单元格,而ZIP则需要R1..R3,L1..L3,X1..X3。所以在这里,WAM更加节省空间。而且,WAM允许进行环境修整(对于更复杂的情况),这对于ZIP来说是不可能的。

呼叫r之前:

r是最后一个调用,并且如果不存在选择点,系统将尝试释放此子句的空间。

对于WAM,存在变量X1..X3 have to be checked仍然是未实例化的局部变量(put_unsafe),如果存在,则将它们移到堆上-这很昂贵,但很少发生。 L1..L3刚刚加载。就是这样,WAM现在可以安全地重新分配本地帧。因此,最后一次通话优化非常便宜。

对于ZIP,一切都必须照常进行。然后只有额外的扫描才能检查堆栈中的所有值,并相应地移动它们。那是相当昂贵的。可以进行一些优化,但仍然远远超出WAM的功能。 ((可能的改进是按相反的顺序推送参数。然后,变量L1..L3可能留在了它们的位置。因此这些变量将不需要任何处理。我还没有看到这样的实现(尚未)。)

关于prolog - WAM的替代品,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4478615/

10-13 04:53