List Prolog中列表中元素的总和

List Prolog中列表中元素的总和,list,prolog,List,Prolog,此代码返回true。如果我将Total=Head+Sum1替换为Total is Head+Sum1,则它将返回该值。但是我应该用什么来代替它来得到这样的结果: list_sum([], 0). list_sum([Head | Tail], TotalSum) :- list_sum(Tail, Sum1), Total = Head + Sum1. 请注意,在过程的第二个子句中,TotalSum从未实例化。您应该在查阅代码时收到解释器的警告 以下是我的建议: ?- list

此代码返回
true
。如果我将
Total=Head+Sum1
替换为
Total is Head+Sum1
,则它将返回该值。但是我应该用什么来代替它来得到这样的结果:

list_sum([], 0).
list_sum([Head | Tail], TotalSum) :-
    list_sum(Tail, Sum1),
    Total = Head + Sum1.

请注意,在过程的第二个子句中,TotalSum从未实例化。您应该在查阅代码时收到解释器的警告

以下是我的建议:

?- list_sum([1,2,0,3], Sum).
Sum = 1+2+0+3 ; % not to return value 6!!!
第一个子句处理基本情况,当列表中只剩下一个元素时,即结果


第二个子句处理递归步骤。它获取列表的前两项并执行递归调用,将这两项替换为新的术语Item1+Item2。

如果要将数字列表转换为加法表达式,请从

list_sum([Item], Item).
list_sum([Item1,Item2 | Tail], Total) :-
    list_sum([Item1+Item2|Tail], Total).

1+2+3

您可以这样做,使用类似于差异列表的内容:

或者,您可以使用累加器:

我相信您会发现第一种样式不是正确的尾部递归,因此不会通过尾部递归优化(TRO)优化到循环中——因此,如果列表足够长,将导致堆栈溢出。第二种方法应该应用TRO,并且应该适用于任何长度的列表

你可能会问,什么是TRO?这是:

在计算机科学中,尾部调用是发生在另一个内部的子程序调用 过程和生成返回值,然后由 调用过程。然后,呼叫站点被称为处于尾部位置,即在呼叫结束时 调用过程。如果子例程对自身执行尾部调用,则调用它 尾部递归。这是递归的一个特例

尾部调用非常重要,因为它们可以在不添加新堆栈的情况下实现 帧到调用堆栈。当前程序的大部分框架都不需要 更多,它可以替换为尾部调用的框架,并根据需要进行修改 (类似于进程的覆盖,但用于函数调用)。然后程序可以跳转到 被调用的子例程。调用生成这样的代码而不是标准调用序列 尾部调用消除,或尾部调用优化

答案很简单:

list_to_additive_expr( Xs , Expr ) :-
  list_to_additive_expr( Xs , 0 , Expr )
  .

list_to_additive_expr( []     , Expr , Expr ) .
list_to_additive_expr( [X|Xs] , RHS , Expr ) :-
  sum_of( Xs , X + RHS , Expr )
  .
这段代码只在一个方向上工作-这意味着-它不允许您生成具有该特定总和的列表。但由于这类列表的集合是无限的,因此无论如何都不实用。

在Prolog
(+)/2
中是一个二进制中缀运算符。这允许我们编写
A+B
,而不是
+(A,B)

示例查询:

list_sum([X|Xs],S) :-
   list_sum0_sum(Xs,X,S).

list_sum0_sum([],    S ,S).
list_sum0_sum([X|Xs],S0,S) :-
   list_sum0_sum(Xs,S0+X,S).
节目是

?- list_sum([1,2,0,3],S).
S = 1+2+0+3.
现在如果查询是

list_sum([],0).

list_sum([Head|Tail], TotalSum):-
list_sum(Tail, Sum1),
TotalSum is Head+Sum1.
答案是

?- list_sum([1,2,3,4], Sum).

至少在SWI Prolog中,用于计算write
总计的值为Head+Sum1
,而不是使用
=
符号。使用尾部递归优化重新思考这一点的线索是有效的,但如果你只是试图学习声明式编程,它们就不是本质,因为现实的弱点是真正的声明式编程不存在,因此Prolog和任何其他语言都有弱点,例如计算的过程顺序,在这种情况下,哪个是次优的。“此代码返回true。”--对于哪个查询?TRO通常被称为TCO(尾部调用优化)。基本情况不应该是空列表吗?首先,应该有一个算术赋值,
is/2
,而不是
+
。如果列表为空-这将失败,而不是返回0。@shybovycha:请重新阅读问题。OP想要得到的是
Total
中的和的表达式,而不是实际的和。@gusbro是的,没错。那么这个解决方案很好,除了开始时的零值(因为即使在表达式形式中,空列表的和仍然是零)=@shybovycha:我想空列表应该给出0作为表达式还是完全失败是有争议的。当我写下那个答案时,我认为正确的做法是失败,因此我提出了那个基本情况。但是同样,可能有人想要得到一个空列表的
0
。在这种情况下,只需添加一个新的基本情况(不要覆盖给定的基本情况,而是添加另一个基本情况),作为
list\u sum([],0)
list_sum([X|Xs],S) :-
   list_sum0_sum(Xs,X,S).

list_sum0_sum([],    S ,S).
list_sum0_sum([X|Xs],S0,S) :-
   list_sum0_sum(Xs,S0+X,S).
?- list_sum([1,2,0,3],S).
S = 1+2+0+3.
list_sum([],0).

list_sum([Head|Tail], TotalSum):-
list_sum(Tail, Sum1),
TotalSum is Head+Sum1.
?- list_sum([1,2,3,4], Sum).
Sum = 10