2

您好,谁能帮我计算前 n 个数字的总和。例如 n=4 => sum = 10。到目前为止我已经写了这个

    predicates
  sum(integer,integer)
clauses

  sum(0,0).
   sum(N,R):-
        N1=N-1,
        sum(N1,R1),
        R=R1+N.

这个可行,但我需要另一种实现。我不知道如何使这有所不同。请帮忙

4

5 回答 5

6

@mbratch 说了什么。

你正在计算的是一个三角数。如果你的作业是关于三角数而不是学习递归思维,你可以简单地计算它:

triangular_number(N,R) :- R is N * (N+1) / 2 .

如果,更有可能的是,你正在学习递归思维,试试这个:

 sum(N,R) :-    % to compute the triangular number n,
   sum(N,1,0,R) % - invoke the worker predicate with its counter and accumulator properly seeded
   .

 sum(0,_,R,R).     % when the count gets decremented to zero, we're done. Unify the accumulator with the result.
 sum(C,X,T,R) :-   % otherwise,
   C > 0 ,         % - assuming the count is greater than zero
   T1 is T+X ,     % - increment the accumulator
   X1 is X+1 ,     % - increment the current number
   C1 is C-1 ,     % - decrement the count
   sum(C1,X1,T1,R) % - recurse down
   .               % Easy!

编辑添加:

或者,如果您更喜欢倒计时方法:

 sum(N,R) :- sum(N,0,R).

 sum(0,R,R).       % when the count gets decremented to zero, we're done. Unify the accumulator with the result.
 sum(N,T,R) :-     % otherwise,
   N > 0 ,         % - assuming the count is greater than zero
   T1 is T+N ,     % - increment the accumulator
   N1 is N-1 ,     % - decrement the count
   sum(N1,T1,R)    % - recurse down
   .               % Easy!

这两个都是tail-recursive,这意味着 prolog 编译器可以将它们变成迭代(google “tail recursion optimization” 了解详细信息)。

如果要消除累加器,则需要执行以下操作:

sum(0,0).
sum(N,R) :-
  N > 0 ,
  N1 is N-1 ,
  sum(N1,R1) ,
  R is R1+N
  .

稍微简单一点,但每次递归都会消耗另一个堆栈帧:给定足够大的 N 值,执行将因堆栈溢出而失败。

于 2014-01-09T23:04:36.217 回答
3
sum(N, Sum) :-
    Sum is (N + 1) * N / 2 .
于 2014-01-10T10:10:59.030 回答
2

既然你已经得到了很多关于你的代码的建议,那么让我抛出一个片段(有点离题)。

计数,更一般地说,聚合,与其他关系、声明性语言(阅读 SQL)相比,这是 Prolog 不发光的领域。但是一些供应商特定的使它更令人愉快:

?- aggregate(sum(N),between(1,4,N),S).
S = 10.
于 2014-01-10T13:57:18.150 回答
1

这是您的程序的“心脏”:

sum(N,R):-
    R=R+N,
    N=N-1,
    sum(N,R).

=/2谓词(注意它接受 2 个参数的方式/2)是实例化谓词,而不是赋值或逻辑相等。它试图统一其论点以使它们相同。因此,如果N不是0,那么R=R+N将永远失败,因为R永远不会与 相同R+N。同样对于N=N-1: 它总是会失败,因为N并且N-1永远不会相同。

=/2(unification)的情况下,计算表达式。它们只是条款。所以 if Y = 1, thenX = Y + 1统一X1+1一个术语(等效写为+(1,1))。

因为以上问题,sum总会失败。

算术表达式的数值赋值是在 Prolog 中使用is/2谓词完成的。像这样:

X is Y + 1.

此运算符将的值统一X为与计算表达式的值相同Y+1X is X+1在这种情况下,由于上面给出的相同原因,您也不能拥有:X不能与 Prolog 相同,X+1并且 Prolog 不允许在子句内“重新实例化”变量。所以你需要类似的东西,X1 is X + 1. 另请注意,is/2要正常工作,右侧表达式中的所有内容都必须事先实例化。如果右侧表达式中的任何变量都没有值,则会出现实例化错误,或者在 Turbo Prolog 的情况下,表达式中的自由变量...。

因此,您需要为表达式结果使用不同的变量,并组织代码,以便在使用is/2时实例化表达式中的变量。


编辑

我从 Sergey Dymchenko 那里了解到,与 GNU 或 SWI 不同,Turbo Prolog 会评估=/2. 所以这=将在给定的问题中起作用。但是,关于实例化(或“自由变量”)的错误仍然是由我上面提到的相同问题引起的。

于 2014-01-09T22:23:32.977 回答
0
sum(N, N, N).  
sum(M, N, S):-
  N>M,
  X is M+1,
  sum(X, N, T),
  S is M+T.


?- sum(1,5,N).
   N = 15 .
于 2018-07-17T04:38:52.020 回答