只要第三个参数没有实例化,它就可以正常工作。这里的危险是如果有办法回溯到第二个规则,或者第三个参数被实例化为与第二个相同的值。这看起来不是特别安全,因为max(X, Y, Y). 等于max(_, Y, Y),它只是将结果设置为第二个值,而不加任何考虑。第一条规则末尾的剪切有效地确保了如果 X >= Y 则不会开始回溯,因此只有在 X
虽然它主要是有效的,但这并不是一个好习惯。刚接触 Prolog 的人倾向于在程序上思考并利用这样的剪辑来通过程序诡计确保特定结果最终使您退缩并导致无法以不同和有趣的方式驱动的复杂 Prolog。还有其他几种编写此谓词的方法同样有效,但不依赖于切割来确保它们的行为,例如:
max(X, Y, X) :- X >= Y.
max(X, Y, Y) :- X < Y.
或
max(X, Y, Z) :- X >= Y -> Z = X ; Z = Y.
这些都不容易受到第三个被实例化的问题的影响。有趣的是,这很好地说明了红色切割和绿色切割之间的区别。您的代码有一个红色剪切,其行为取决于剪切,但如果我只是将我的第一个解决方案更改为:
max(X, Y, X) :- X >= Y, !.
max(X, Y, Y) :- X < Y.
这是一个绿色剪切,因为行为不依赖于剪切,但 Prolog 的性能可能会略有提高,因为它不会回溯到第二个子句尝试它。在这里,我们明确告诉 Prolog,不要同时进行下一次检查,因为我们知道它会失败。使用红色切口,没有其他检查会失败。
不幸的是,将条件陈述两次让人感觉多余,但依靠单一规则却感觉很笨拙。在实践中,我的经验是,这样的场景最终并不是那么普遍。通常,您可以在子句的头部匹配原子或结构,这些原子或结构可以创建类似于我们在我的第一个替代项中的行为,但不需要主体。例如:
perform(scan(target, X, Y)) :- ...
perform(scan(calibration, X)) :- ...
这样的效果是一样的:Prolog会回溯,直到统一成功,然后再回溯,但是匹配的排他性会阻止另一个body被执行。如果我们发现回溯花费了太多时间,我们可以添加削减以提高性能,但实际上这不太可能成为问题。