Prolog:使用一次性规则在列表上递归

Prolog: Recursion on a list with one one-time rule

很可能我无法正确地表达我的搜索关键字。我想做的是递归地评估列表中连续条目的差异,并将它们添加到全局计数器中。挑战在于最后的循环子句,以便如果列表是 [5,4,3,2,1],则谓词应该 return (5-4)+(4-3)+(3-2)+(2-1)+(1-5)=0.

目前我的情况如下:

circularSumOfDifferences([_],0).
circularSumOfDifferences([E1,E2|List],Sum) :-
    Diff is E1-E2,
    circularSumOfDifferences([E2|List],SoD),
    Sum is Diff+SoD.

现在我想到了定义另一个谓词以将列表的第一个元素添加到给定列表的尾部并结合查询调用新列表:copyHeadToTail([5,4,3,2,1],Result),circularSumOfDifferences(Result,C).

实现起来不难,但对我来说看起来不是很优雅。我想知道是否有一种方法可以只定义一个谓词 circularSumOfDifferences(+L,-SoD),它在列表中递归并在最后(或开始)为那个减法运行一个语句,即1-5.

当然,您可以编写一个谓词来做到这一点,但是您应该注意到列表的每个元素 X 在总和中出现了两次,一次是 X 一次是-X。无论您为该谓词提供什么数字列表,结果始终为 0。那是作业吗?很可能重点是注意到这一点,而不是试图计算实际总和:

always_zero([], 0).
always_zero([X|Xs], 0) :-
    number(X),
    always_zero(Xs, 0).

如果您坚持要写谓词,请按以下方式编写:

circ_sum_of_diff([X|Xs], Sum) :- % must have at least one element I guess?
    circ_sum_of_diff_1(Xs, X, X, 0, Sum).

circ_sum_of_diff_1([], Last, First, SoFar, Sum) :-
    Sum is SoFar + Last - First.
circ_sum_of_diff_1([X|Xs], X0, First, SoFar0, Sum) :-
    SoFar is SoFar0 + X0 - X,
    circ_sum_of_diff_1(Xs, X, First, SoFar, Sum).

这使用了一个辅助谓词,这在 Prolog 程序中很常见。实际遍历列表的辅助谓词有三个额外的参数:列表的解包头、原始第一个元素(在列表末尾使用)和到目前为止的总和。