2014-01-09 61 views
1

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

predicates 
    sum(integer,integer) 
clauses 

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

这一件作品,但我需要另一种实现方式。我没有任何想法,我可以做出这种差异。请帮助

+0

当您运行程序时发生了什么? – lurker

+0

你能否编辑你的代码以明确什么是评论和代码?这个文件不会按原样加载/编译。 –

+2

@ChristianF这似乎是Visual Prolog,它使用了命名部分并允许定义'domains'部分中的数据类型。这有点不合标准。上面的代码是语法上有效的Visual Prolog代码(拼写错误的“intger”)。 – lurker

回答

2

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

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:它总是会失败,因为NN-1永远不会相同。

=/2(统一)的情况下,表达式为而不是评估。他们只是条款。因此,如果Y = 1,那么X = Y + 1统一X1+1作为一个术语(等效地写为+(1,1))。

由于上述问题,sum将始终失败。

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

X is Y + 1. 

这个操作符统一X值设定为相同的评价表达Y+1的值。在这种情况下,出于上面给出的相同原因,您也不能有X is X+1X不能与X+1相同,并且Prolog不允许子句内的变量“重新实例化”。所以你需要像X1 is X + 1这样的东西。还要注意,要使is/2正常工作,右侧表达式中的所有内容都必须预先实例化。如果右侧表达式中的任何变量没有值,您将得到一个实例化错误,或者在Turbo Prolog的情况下,表达式中的自由变量...

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


编辑

我塞吉Dymchenko了解到,睿频Prolog的,不像GNU或SWI,计算表达式为=/2。所以=将工作在给定的问题。然而,关于实例化(或“自由变量”)的错误仍然是由我上面提到的相同问题引起的。

+0

我试过这个但仍然没有工作总和(N,R): - P = R + N, N1 = N-1, sum(N1,P)。 – user3043278

+0

@ user3043278查看有关'=/2'与'is/2'的答案。另请参阅关于“表达式中的自由变量”原因的描述。首先,您需要'is'而不是'='。 '='不是正确的谓词。其次,按照它们存在于你的子句中的顺序,由于实例化(自由变量)错误,“is”将失败。 – lurker

+0

mbratch,Visual Prolog(和Turbo Prolog)是一个有趣的东西,=/2被用来代替is/2:参见http://progopedia.com/implementation/visual-prolog/ –

5

@mbratch说什么。

你计算的是一个triangular number。如果你的功课是关于三角数,而不是对学习递归的思维,你可以简单地这样计算它:

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! 

这两个都是尾递归,这意味着prolog编译器可以将它们变成迭代(谷歌“尾递归优化”的细节)。

如果你想消除蓄能器,你需要做的是这样的:

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

一点点简单的,但每个递归使用另一栈帧:给N个足够大的值,执行将堆栈溢出失败。

+0

我不明白你为什么使用X和T.我理解了总和的递归算法,但我不知道如何在Prolog中编写它。如果我的号码大于1,我将这个号码加到结果中,然后调用sum(number-1)。 – user3043278

+1

@ user3043278:我宁愿数起来,而不是倒数。一个六个;正如他们所说,另一半是另一半。我已经添加了一个简单的倒计时版本到我的答案。还增加了一些更接近你最初的解释,为什么我采取了我做的方法。 –

1
sum(N, Sum) :- 
    Sum is (N + 1) * N/2 . 
+0

请提供一些更详细的信息。 – Max

+1

@MaxMommersteeg:请参阅[算术级数总和](http://en.wikipedia.org/wiki/Arithmetic_progression#Sum)。 – salva

+0

我相信尼古拉斯给出的答案已经指出了。 ;) – lurker

1

既然你已经有了很多关于你的代码的建议,那就让我把代码片断(有点偏离主题)。

计数和更普遍的聚合是Prolog在与其他关系型声明性语言(读取SQL)相比较时不会发光的区域。但某些特定供应商library使其更令人愉快:

?- aggregate(sum(N),between(1,4,N),S). 
S = 10.