在Warren的抽象机中,如果其中一个参数是寄存器,绑定是如何工作的?

Orf*_*est 5 prolog unification warren-abstract-machine

我正在尝试创建自己的WAM实现,我坚持练习2.4

我无法理解如何执行unify_value X4图2.4中的指令.

据我所知,该指令应该从查询中用程序中的f(W)统一Y.

unify_value X4调用unify (X4,S)S = 2(见图2.1),相应的堆单元格为"REF 2",X4为"STR 5".

Unify(图2.7)应该bind是那些值,但我不明白如何deref注册.

"REF 2"在堆中,"STR 5"在寄存器中.你怎么bind去登记册?

fal*_*lse 5

我们谈论的是沃伦的"新"引擎,WAM而不是旧引擎,即PLM.

在WAM中,变量分配在两个地方.

  1. 本地堆栈(环境堆栈)

寄存器不能保存变量.但是,它们可能包含对变量的引用.请注意,来自堆的引用仅指向堆.

与您的问题有很大关系的是WAM维护此顺序的非常巧妙的方式,同时具有非常便宜的最后调用优化.在(确定的)最后一次调用的时间点,必须以某种方式移动作为最后一次调用的参数的局部变量.在像ZIP这样的传统Prolog机器中,这是一项非常费力的工作,其基本上需要扫描环境框架以查找仍然存在于其中的变量.

然而,WAM有一个更好的调用约定:大多数变量已经处于安全的地方,可以在编译期间进行简单的分析.剩下的极少数需要一个显式的PUT_UNSAFE指令来检查值,并且它仍然是一个局部变量,该变量被转移到堆上.

考虑WAM中的安全变量:

  1. 所有变量都发生在头部

  2. 所有变量都显示为结构的参数

因此,只有在目标和最后一个目标中出现并且未出现在某个结构中的变量必须具有PUT_UNSAFE.那不是那么多.此外,动态检查可以将堆上的实际复制减少到最小.

起初这个PUT_UNSAFE看起来很多工作,但永远不要忘记WAM允许删除许多PUT,而ZIP必须为每个参数执行至少一条指令.

这是使用GNU的一个很小的典型示例:

a --> b, c.
Run Code Online (Sandbox Code Playgroud)

扩展到:

a(S0,S) :- b(S0,S1), c(S1,S).
Run Code Online (Sandbox Code Playgroud)

并使用以下命令编译pl2wam:

predicate(a/2,1,static,private,monofile,global,[
    allocate(2),
    get_variable(y(0),1),                   % S
    put_variable(y(1),1),                   % S1
    call(b/2),
    put_unsafe_value(y(1),0),               % S1
    put_value(y(0),1),                      % S
    deallocate,
    execute(c/2)]).

  • 谢谢你写得这么好. (2认同)