如何使用Prolog';s的逻辑更新视图是否适用于断言和收回?
有人能详细解释一下关于断言和收回的序言逻辑视图吗 例如,在下面的代码中,在第一次运行时,Prolog返回true,在后续运行时,Prolog返回false。我不知道为什么当如何使用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
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).