受@MatsCarlsson 版本的启发,我尝试尽量减少涉及的约束变量的数量:
applyConstraints(Xs) :-
S #\= R,
applyConstraints(Xs, S, R).
applyConstraints([], _, _).
applyConstraints([X|Xs], S, R) :-
X mod 2 #= S,
applyConstraints(Xs, R, S).
编辑:这个版本对于目标applyConstraints([]) 有一个不明显的缺陷。实际上,需要在 SICStus 中切换到full_answer 模式,如下所示:
| ?- applyConstraints([]).
yes
| ?- assertz(clpfd:full_answer).
yes
| ?- applyConstraints([]).
clpfd:(_A#\=_B),
_A in inf..sup,
_B in inf..sup ? ;
no
所以我们有这个无用的约束,它可能会消耗资源。
为了克服这个缺陷,需要一些特殊的外壳:
applyConstraints([]).
applyConstraints([X|Xs]) :-
X mod 2 #= S,
S #\= R,
applyConstraints(Xs, R, S).
注意 1 — 在 SWI 或 YAP 中,没有直接的方法可以打开完全应答模式。解决问题的唯一方法是将查询包裹在 call_residue_vars/2 周围,如下所示:
?- applyConstraints([]).
true.
?- call_residue_vars(applyConstraints([]),RVs).
RVs = [_G794, _G797],
_G794#\=_G797.
注意 2 — 感谢 @mat,自 SWI 7.3 以来有类似的功能(请记住,SWI 7 需要 --traditional 以实现兼容性):
?- set_prolog_flag(toplevel_residue_vars, true).
true.
?- applyConstraints([]).
% with detached residual goals
_G430#\=_G433.
(在这种情况下,“分离”应该是什么意思还不是很清楚,毕竟剩余的目标必须为真,才能使答案为真。所以不涉及分离。 )