Prolog中列表中元素的总和

时间:2012-03-26 16:14:36

标签: list prolog

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

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

?- list_sum([1,2,0,3], Sum).
Sum = 1+2+0+3 ; % not to return value 6!!!

5 个答案:

答案 0 :(得分:21)

答案很简单:

sum_list([], 0).
sum_list([H|T], Sum) :-
   sum_list(T, Rest),
   Sum is H + Rest.

此代码仅在一个方向上起作用 - 这意味着 - 它不允许您生成具有该特定总和的列表。但由于这些列表的集合是无限的,所以无论如何这都不实用。

答案 1 :(得分:8)

请注意,在您的过程的第二个子句中,TotalSum永远不会被实例化。在咨询您的代码时,您应该已经收到口译员的警告。

这是我的建议:

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

第一个子句处理基本情况,当列表中只剩下一个元素时,就是你的结果。

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

答案 2 :(得分:2)

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

?- current_op(_,yfx,+).   % left-associative binary infix operator
true.

(+)/2关联到左侧,因此1+2+3(1+2)+3的缩写。

(.)/2权利相关联,因此[1,2,3].(1,.(2,.(3,[])))的缩写。

为了使括号正确,我们使用带有额外“accumulator”参数的辅助谓词:

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.

答案 3 :(得分:1)

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

开始
[1,2,3]

1 + 2 + 3

你可以使用像差异列表这样的东西来做这样的事情:

list_to_additive_expr( [] , 0 ).
list_to_additive_expr( [X|Xs] , X + RHS ) :-
  sum_of( Xs , RHS ).

或者,您可以使用累加器

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 )
  .

我相信你会发现第一个样式没有正确尾递归,所以不会通过尾递归优化(TRO)优化成循环 - 和所以,如果列表足够长,将会出现堆栈溢出。第二种方法应该应用TRO,并且应该适用于任何长度的列表。

你可能会问,什么是TRO?这是Wikipedia with an answer for you

  

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

     

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

答案 4 :(得分:1)

该计划

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
相关问题