给定一组通过谓词 parent / 2 表示父子关系的事实,在使用谓词定义关系"祖先"(祖先)时有什么不同 pred1 / 2 和 pred2 / 2 如下所示?
pred1(X,Z) :- parent(X,Z).
pred1(X,Z) :- parent(X,Y), pred1(Y,Z).
pred2(X,Z) :- parent(X,Z).
pred2(X,Z) :- parent(Y,Z), pred2(X,Y).
答案 0 :(得分:4)
主要区别在于两者的终止属性,前提是关系中存在一些循环。为了理解这一点,我将使用failure-slice来减少程序的本质w.r.t.终止。
pred1(X,Z) :- false, parent(X,Z). pred1(X,Z) :- parent(X,Y), pred1(Y,Z). % Z has no influencepred2(X,Z) :- false, parent(X,Z). pred2(X,Z) :- parent(Y,Z), pred2(X,Y). % X has no influence
对于pred1/2
,第二个参数根本不影响终止,而在pred2/2
中,第一个参数没有影响。要查看此内容,请使用以下事实尝试原始定义:
parent(a,a). ?- pred1(b, _), false. % terminates ?- pred2(b, _), false. % loops ?- pred1(_, b), false. % loops ?- pred2(_, b), false. % terminates
有关避免此类循环的一般方法,请参阅closure/3
。
为了完整性,这里是传递闭包的另一种变体,它具有一些概念上的优点:
pred3(X,Z) :- parent(X,Z).
pred3(X,Z) :- pred3(X,Y), pred3(Y,Z).
唉,它的终止属性最差。事实上,永远终止,正如以下片段所证实的那样:
pred3(X,Z) :- false, parent(X,Z). pred3(X,Z) :- pred3(X,Y), false,pred3(Y,Z).
在此片段中,仅传递第一个参数。所以,无论参数是什么,程序总会循环!
?- pred3(b,b), false. % loops