我们谈论的是 Warren 的“新”引擎 WAM,而不是旧引擎,即 PLM。
在 WAM 中,变量被分配在两个地方。
本地栈(环境栈)
堆
寄存器不能保存变量。但是,它们可能包含对变量的引用。请注意,来自堆的引用仅指向堆。
与您的问题非常相关的是 WAM 如何维护此顺序的非常巧妙的方式,同时具有非常便宜的 last-call optimization。在(确定的)最后一次调用的时间点,作为最后一次调用的参数的局部变量必须以某种方式移动。在更传统的 Prolog 机器(如 ZIP)中,这是一项极其费力的工作,基本上需要扫描环境框架以查找仍然存在于其中的变量。
然而,WAM 有一个更好的调用约定:大多数变量已经在一个安全的地方,可以在编译期间进行简单的分析。剩下的极少数需要一个显式的 PUT_UNSAFE 指令来检查值,并且如果它仍然是一个局部变量,那么该变量会被转移到堆上。
考虑什么是 WAM 中的安全变量:
发生在头部的所有变量
作为结构参数出现的所有变量
因此,只有首先出现在目标和最后一个目标中且未出现在某些结构中的变量必须具有 PUT_UNSAFE。那不是那么多。此外,动态检查可以将实际复制到堆上的操作减少到最低限度。
起初,这个 PUT_UNSAFE 看起来工作量很大,但永远不要忘记 WAM 允许删除许多 PUT,而 ZIP 必须为每个参数执行至少一条指令。
这是一个使用GNU的小典型示例:
a --> b, c.
扩展为:
a(S0,S) :- b(S0,S1), c(S1,S).
并使用以下命令编译pl2wam
:
谓词(a/2,1,静态,私有,单文件,全局,[
分配(2),
get_variable(y(0),1), % S
put_variable(y(1),1), % S1
通话(b/2),
put_unsafe_value(y(1),0) , % S1
put_value(y(0),1), % S
解除分配,
执行(c/2)])。