从历史的角度来看,逻辑更新视图首先在 Quintus 2.0(其当前的继任者是 SICStus)中实现,并在 1987 年的文献中进行了描述。它已在 ISO Prolog ISO/IEC 13211-1:1995 中采用。主要思想是,动态谓词的任何目标都将准确考虑执行目标时出现的那些子句。任何进一步的更改——无论是添加还是删除——都不会在执行该目标时考虑在内。
在逻辑更新视图之前,已经有各种或多或少一致的实现,大多数与 Prolog 系统的各种优化不兼容。请注意,仅当您的目标可能有多个答案时,差异才会显示出来。无论是作为一个简单的目标,还是在使用retract并且您正在使用retract/1
or时assertz/1
。仅使用时不会显示差异asserta/1
。因此,您的示例无法阐明差异。
考虑一个动态谓词p/1
。由于以下交互仅使用顶层,我将p/1
通过断言一个事实并立即收回所有事实来让系统知道p/1
。retractall(p(_))
此外,在开始下一个查询之前,我将删除所有事实。
?- asserta(p(1)).
true. % now p/1 is known to the system.
?- retractall(p(_)), assertz(p(1)), p(X), assertz(p(2)).
X = 1. % only one answer!
?- retractall(p(_)), assertz(p(1)), p(X), assertz(p(2)), p(Y).
X = 1, Y = X ;
X = 1,
Y = 2.
所以第一个目标p(X)
只看到p(1)
,而第二个目标p(Y)
两者都看到。这适用于任何主动目标:
?- retractall(p(_)), assertz(p(1)), assertz(p(2)), p(X), assertz(p(3)), p(Y).
X = 1, Y = X ;
X = 1,
Y = 2 ;
X = 1,
Y = 3 ;
X = 2,
Y = 1 ;
X = 2, Y = X ;
X = 2,
Y = 3 ;
X = 2,
Y = 3 ;
false.
同样,请注意X
只有 1 或 2 而不是 3。
或者,您可以想象每个目标p(X)
都替换为:
... findall(Xi, p(Xi), Xis), member(X, Xis) ...
这向您展示了一些背后的想法:从概念上讲,所有答案都是临时存储的,然后才显示每个答案。
呃,上面说的不太对,只有of的子句是p/1
这样处理的。也就是说,只要你只存储事实,上面的解释是完美的,但如果你还存储规则,你将需要一个更复杂的解释,大致:
... findall(Xi-Bi, clause(p(Xi),Bi), XiBis), member(X-B,XiBis), B ...
而且,再一次,这不是显而易见的事实,因为削减等一些更奇特的问题可能会介入。我将暂时保持这种状态1。
同样,retract/1
也会看到并删除它在执行时看到的子句。对于大多数情况,这是非常直观的,并且符合我们的期望。然而,也有以下相当荒谬的情况:
?- retractall(p(_)),
assertz(p(1)), assertz(p(2)),
retract(p(X)), ( X = 1, retract(p(Y)) ; X = 2, Y = none ).
X = 1,
Y = 2 ;
X = 2,
Y = none.
这里,事实p(2)
被删除了两次,尽管数据库只包含一个事实p(2).
脚注
1 实际上,替换
... p(X) ...
经过
... findall(Xi-Bi, clause(p(Xi),Bi), XiBis), answs_goal_x(XiBis,X, G), G ...
和
answs_goal_x([], _, true).
answs_goal_x([Xi-Bi|XiBis], X, ( X = Xi, Bi ; G) ) :-
answs_goal_x(XiBis, X, G).