Prolog中处理“剩余目标”的方法是什么?
以这个程序为例。它使用延迟目标
room(green).
room(blue).
room(red).
room(white).
location(jimmy,red).
location(ricky,blue).
location(cindy,green).
% "Is a certain room unoccupied?"
not_occupied(Room) :-
nonvar(Room),
assertion(room(Room)),
+ location(_Person,Room).
% If no specific "Room" has been given, the negated goal is
% delayed until the "Room" has been instantiated.
not_occupied(Room) :-
var(Room),
!,
when(
ground(Room),
(+ location(_Person,Room))
).
如果我现在问
?- not_occupied(R).
然后 Prolog 成功并输出一个残差目标
?- not_occupied(R).
when(ground(R),+location(_7676,R)).
实际上,它并没有真正成功。它乐观地成功(因为为了不停止计算,它必须成功)但实际的逻辑成功取决于剩余目标的实际成功。
如何以编程方式找出子目标是否成功实现剩余目标?(然后我该怎么办?) 方法是什么?
聚苯乙烯
具有辅助 Prolog 真值可能是一个不错的 Prolog 扩展,因为 atrue+表示“在剩余目标成功的情况下成功”。这实际上似乎有一定的必要性:
在 SWI-Prolog 中,采用这个固有的模糊目标:
do :- not_occupied(_).
调用它甚至根本不会打印出任何剩余目标:
?- do.
true.
目标成功了吗?不是真的,它仍然处于逻辑边缘,但顶层甚至没有告诉我。另一方面,没有办法向程序提供更多信息来解决剩余目标。但是默认为“成功”,因为计算运行到最后感觉是错误的。
回答
首先是一些术语问题。我们从顶层得到的是一个答案。说:
?- length(Xs, 0).
Xs = [].
在这里,答案采用答案替换的形式,它描述了一个解决方案。
?- length(Xs, 1).
Xs = [_A].
同样,这是一个答案替换,但这次它描述了无限多个解决方案。
答案和解决方案的概念通常可以互换使用,但是一旦我们使用延迟目标或约束,我们就需要明确区分。现在的新情况是答案可能包含任意数量的解决方案,包括根本没有。
?- freeze(X, false).
freeze(X,false). % no solution
?- freeze(X, ( X = 1 ; X = 2 ) ).
freeze(X,(X=1;X=2)). % two solutions
一些实现仅提供frozen(Var, Goal)与Var. 在这种情况下,内置了call_residue(Goal_0, Residuum)。最初,在 SICStus 0.7 中,它是为延迟目标定义的,因为残差定义得非常好。然而,一旦我们将我们的语言扩展到 clpfd,事情就不那么清楚了。这是 SICStus 3.12.5:
| ?- X in 1..3, call_residue(X in 2..4, Residuum).
Residuum = [[X]-(X in 2..3),
X in 1..3 ?
残差现在应该是X in 2..3还是X in {1}?事情可能会变得非常复杂(阅读:越野车)。此外,取消绑定非常费力;或者实现首先创建整个目标的副本,然后保留约束。
SICStus 4 被call_residue/2两个新的内置程序所取代。与与 中创建的延迟目标或约束相关的变量call_residue_vars(Goal_0, Vars)统一。请注意,当某些受约束的变量存在于 之前并出现在 中时,此概念并不那么精确。但主要的一点是,这个内置的实现成本相对较低。它不复制或任何子条款。VarsGoal_0Goal_0Goal_0Goal_0
另一个是copy_term(Term, Copy, G_0s)可用于通过调用maplist(call, G_0s)(在 SWI 中,Scryer)或call(G_0)(在 SICStus 中)来重建附加约束。在 SWI (clpfd) 和 Scryer (clpz) 的实现中,V in inf..sup投影省略了一些形式的冗余约束。但投影实际上是另一个问题。