问题描述
这个谓词有两个子句:
abs(X,Y) :- X < 0,Y is -X.
abs(X,X) :- X >= 0.
然后我将其提交给口译员:
?- abs(-5,W).
W = 5 ;
false.
?-
为什么它评估第二个子句并返回false?有办法解决吗?
解决方法
您写了两个在第一个参数 (X
) 上不相交的子句,并且很惊讶 Prolog 回溯到第二个参数,即使第一个参数已经满足。
abs(X,Y) :- X < 0,Y is -X.
abs(X,X) :- X >= 0.
当第1个子句满足时,Prolog引擎只知道有第2个子句没有被求值;当您输入“;
”时,它尝试了第二个子句,但失败了。要了解原因,请考虑您的代码的一个略有不同(并且没有那么好)的版本:
abs2(X,Y) :- X =< 0,Y is - X.
abs2(X,Y) :- X >= 0,Y = X.
?- abs2(0,Y).
Y = 0 ;
Y = 0 ;
在这种情况下,即使第一个子句成功,第二个子句也可以成功。
那么,如何避免这种情况呢?这取决于你想完成什么。如果您想获得所有答案,请执行以下操作:
?- setof(W,abs(-5,W),Ws).
Ws = [5].
要全部打印:
?- forall(abs(-5,format('W = ~q~n',[W])).
W = 5
如果你想告诉 Prolog 引擎你的谓词是确定性的,你可以使用 if-then-else:
abs(X,Y) :-
( X < 0
-> Y is -X
; Y = X
).
这也可以用 cut("!
") 来写,但使用 if-then-else 通常更容易理解。
而且,如果您使用的是最新版本的 SWI-Prolog,则可以使用 "=>
" notation:
abs(X,Y),X < 0 => Y is -X.
abs(X,Y) => true.