您的程序有几个 cmets:
第一,这个名字用词不当。第一个参数是一个列表,第二个是最后一个元素。但你的名字暗示了其他。更好的名字是list_last/2 或简单的last/2。
第二,剪错了。事实上,通过简单地交换规则并删除削减,您将获得显着提高效率和声明性:
last([X] , X).
last([_|Xs], X) :- last(Xs,X).
现在回答你的问题。在 Prolog 中开始编程时,最好先想象 ground 查询。因此,让我们举几个关系应该成功的例子。
?- last([a],a).
要做到这一点,last([a],a). 的事实就足够了。我们可以将这一事实概括到last([X],X).。之后,我们可能会考虑一个包含两个元素的列表,last([_,X],X). 将涵盖所有长度为 2 的列表。等等
last([X],X).
last([_,X],X).
last([_,_,X],X).
...
现在,让我们概括一下这个模式!让我们将较长列表的情况减少为较短的列表。为此,我假设我已经知道Xs 的最后一个元素:
???? :-
last(Xs, X).
当我们已经知道X 是Xs 的最后一个元素时,我们可以得出什么结论?我们可以得出结论,一个长一个元素的列表也将具有与最后一个元素完全相同的X!因此:
last([_|Xs], X) :-
list(Xs, X).
所以有了这个规则,我们可以让列表越来越长。但前提是我们可以从一个案例开始!出于这个原因,你需要list([X],X). 最好先添加这个事实,因为你也会找到目标list(Xs, a) 的答案。
请注意我查看:- 的特殊方式。我把它理解为一个从右到左的箭头,暗示着一些新的东西:如果右边的目标是真实的,那么左边的目标也是真实的。
通常,人们试图完全按照 Prolog 执行规则的方式来理解 Prolog 规则。这不是像我那样从右到左,而是从左到右。然而,这种解读对人类来说是非常不直观的,因为 Prolog 使用了一种非常不寻常的执行方式:一方面它使用比模式匹配然后回溯复杂得多的统一。这两个概念在传统编程语言中都不存在,因此让您感到困惑而不是帮助。