使用“或”运算符和使用多个子句有什么区别吗?
如果有的话,结果和执行有何不同?
memb(X, [Y,L]) :- X == Y ; memb(X,L).
和
memb(X, [Y,L]) :- X == Y.
memb(X, [Y,L]) :- memb(X,L).
回答
没有语义差异,但 调用谓词时可能存在性能差异。让我们用一个例子来说明:
walk([]).
walk([_| Tail]) :-
walk(Tail).
假设 Prolog 系统实现了first-argument indexing,以下查询不会创建任何选择点:
| ?- walk([]).
yes
| ?- walk([_,_,_]).
yes
我们可以将walk/1谓词重写为一个语义等价的子句:
walk(List) :- List = []; List = [_| Tail], walk(Tail).
但现在我们将得到:
| ?- walk([]).
true ? ;
no
| ?- walk([_,_,_]).
true ? ;
no
即我们失去了第一个参数索引在避免创建虚假选择点方面的好处(当调用walk/1带有绑定参数的谓词时)。
编写主体为析取的子句通常不是一个好的编程习惯用法。在大多数情况下,使用单独的子句会使代码更易于阅读并且(如上例所示)更高效。但是大多数编码指南规则都有例外,这里也是如此。有时,一个子句标题与一个或多个参数子项相结合,这是一项成本相对较高的操作。例如:
foo([_, _, Three| _], bar(_, [_, Second]), _) :-
...
这是一个人为的例子,但复杂的头部统一通常可以在非平凡的代码中找到。通过使用单个子句和析取可以避免在多个重复的子句之间进行复杂子句头部统一的成本,因为它只会执行一次(每次调用谓词)。