如何使用Prolog';s的逻辑更新视图是否适用于断言和收回?

如何使用Prolog';s的逻辑更新视图是否适用于断言和收回?,prolog,iso-prolog,prolog-assert,Prolog,Iso Prolog,Prolog Assert,有人能详细解释一下关于断言和收回的序言逻辑视图吗 例如,在下面的代码中,在第一次运行时,Prolog返回true,在后续运行时,Prolog返回false。我不知道为什么当asserta(nextBound(100))满足时,由于Prolog逻辑视图,nice(X)在启动时仍然冻结了值,因此应该忽略此更改,nextBound(100)必须为false nextBound(10000). nice(X) :- asserta(nextBound(100)), retract(next

有人能详细解释一下关于断言和收回的序言逻辑视图吗

例如,在下面的代码中,在第一次运行时,Prolog返回true,在后续运行时,Prolog返回false。我不知道为什么当
asserta(nextBound(100))
满足时,由于Prolog逻辑视图,nice(X)在启动时仍然冻结了值,因此应该忽略此更改,
nextBound(100)
必须为false

nextBound(10000).

nice(X) :-
   asserta(nextBound(100)),
   retract(nextBound(10000)),
   nextBound(100).

您可以执行
跟踪
,以确定发生了什么:

| ?- nice(_).
      1    1  Call: nice(_17) ?
      2    2  Call: asserta(nextBound(100)) ?
      2    2  Exit: asserta(nextBound(100)) ?   <-- 1st assert of netBound(100) succeeds
      3    2  Call: retract(nextBound(10000)) ?
      3    2  Exit: retract(nextBound(10000)) ? <-- retract nextBound(10000) succeeds
      4    2  Call: nextBound(100) ?
      4    2  Exit: nextBound(100) ? <-- Succeeds because netBound(100) now a fact
      1    1  Exit: nice(_17) ?

(1 ms) yes
{trace}
| ?- nice(_).
      1    1  Call: nice(_17) ?
      2    2  Call: asserta(nextBound(100)) ?
      2    2  Exit: asserta(nextBound(100)) ?   <-- 2nd assert of netBound(100) succeeds
      3    2  Call: retract(nextBound(10000)) ?
      3    2  Fail: retract(nextBound(10000)) ? <-- retract nextBound(10000) fails
      1    1  Fail: nice(_17) ?

(3 ms) no
{trace}
| ?-
正如SWI文档中所述,逻辑更新视图表示,从SWI Prolog 3.3.0开始,我们坚持逻辑更新视图,其中输入谓词定义的可回溯谓词将不会看到任何更改(由
断言/1
收回/1
引起)到谓词

换句话说,逻辑更新视图防止谓词在执行时动态更改自身。这里的情况并非如此


事实上,在Prolog中至关重要的是,在谓词执行期间,如果在谓词中的某个点断言一个事实,则该结果必须立即在其中可见,否则谓词可能无法正常运行。有许多常见的库谓词依赖于此行为。

从历史视图开始,逻辑更新视图首先在Quintus 2.0中实现(其当前继承者是SICStus),并在1987年的文献中进行了描述。它已在ISO Prolog ISO/IEC 13211-1:1995中采用。其主要思想是,动态谓词的任何目标都将精确地考虑在执行目标时出现的那些子句。任何进一步的变化——无论是增加还是删除——都不会在执行该目标时考虑在内

在logical update视图之前,有各种或多或少一致的实现,大多数都与Prolog系统的各种优化不兼容。请注意,只有当您的目标可能有多个答案时,差异才会显示出来。作为一个简单的目标,或者在使用retract时,您使用的是
retract/1
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) ...
这向您展示了一点背后的想法:从概念上讲,所有答案都是临时存储的,然后才显示每个答案

呃,上面不太对,因为只有p/1的条款是这样处理的。也就是说,只要您只存储事实,上述解释是完美的,但如果您还存储规则,则需要更复杂的解释,大致如下:

 ... findall(Xi-Bi, clause(p(Xi),Bi), XiBis), member(X-B,XiBis), B ...
再说一次,这并不是显而易见的事实,因为削减开支等更具异国情调的问题可能会介入。我暂时就这样吧

类似地,
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) ...


谢谢,先生,但我认为,由于prolog“nextBound(100)”的逻辑视图,应该在第一次执行时通过nice()计算'false',因为asserta(nextBound(100))在nice()谓词中完成,而nice(u)在当时是冻结的。不是吗?@CoderInNetwork正如您在跟踪中看到的,
nextBound(100)
被评估,并在第一次执行
nice()
时按预期成功,因为它在被查询之前已被断言。@CoderInNetwork,很明显,当执行
nice()
时,它不会在数据库的冻结状态下运行。数据库在执行过程中是动态的。任何断言或收回的事实都会立即执行,随后的查询会看到这些结果。我回答了你的问题吗?亲爱的潜伏者,你的回答很清楚,但这不是与此相矛盾吗?@CoderInNetwork我不认为这是矛盾的。该链接上的评论说,从SWI Prolog 3.3.0开始,我们坚持逻辑更新视图,其中输入谓词定义的可回溯谓词不会看到谓词的任何更改(由
assert/1
retract/1
引起)。换句话说,谓词不能动态更改自己的定义。相对于数据库中该谓词的更改,谓词本身的定义是静态的。如果不是这样的话,那就有点混乱了。谢谢你添加这个答案。历史信息和示例非常有用。(+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).