这个prolog代码背后的逻辑是什么?

时间:2014-03-10 09:22:24

标签: prolog

我有简短的Prolog代码,可以找到给定列表的最后一个元素。

last_of([_|Tail], X) :- last_of(Tail, X), !.
last_of([X], X).

但是我对这个程序的逻辑有疑问。为什么我们使用last_of([X], X).,我无法理解这一点。你能解释一下吗?

2 个答案:

答案 0 :(得分:4)

您的计划有几条评论:

第1,这个名字用词不当。第一个参数是列表,第二个参数是最后一个元素。但是你的名字不然。更好的名称是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).

当我们已经知道XXs的最后一个元素时,我们能得出什么结论?我们可以得出结论,一个元素长的列表也会与最后一个元素具有相同的X!因此:

last([_|Xs], X) :-
   list(Xs, X).

因此,通过此规则,我们可以使列表越来越长。但是只有在有可能从我们开始的情况下!出于这个原因,您需要list([X],X).最好先添加 这个事实,因为您也会找到目标list(Xs, a)的答案。

请注意我查看:-的具体方式。我把它看成是一个从右到左的箭头,意味着一些新的东西:如果右边的目标是真的,那么左边的目标也是如此。

人们经常尝试按照Prolog执行它们的方式来理解Prolog规则。这不是我从右到左,而是从左到右。然而,这种读取对于人类来说非常不直观,因为Prolog使用了一种非常不寻常的方式来执行:一方面它使用统一,这比模式匹配然后回溯要复杂得多。这两种概念都不存在于传统的编程语言中,从而使您感到困惑,而不是他们的帮助。

答案 1 :(得分:1)

Prolog在评估时具有固有的递归性。到达last_of(Tail, X)时 它再次检查last_of(),并将Tail作为新的第一个参数。

显然这需要某种方法来停止,所以你会得到一个断言,即X始终是仅包含X的列表中的最后一个元素。