你好谁能帮我计算前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.
这一件作品,但我需要另一种实现方式。我没有任何想法,我可以做出这种差异。请帮助
你好谁能帮我计算前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.
这一件作品,但我需要另一种实现方式。我没有任何想法,我可以做出这种差异。请帮助
这是你的程序的“心脏”:
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
(统一)的情况下,表达式为而不是评估。他们只是条款。因此,如果Y = 1
,那么X = Y + 1
统一X
与1+1
作为一个术语(等效地写为+(1,1)
)。
由于上述问题,sum
将始终失败。
算术表达式的数值赋值在Prolog中以is/2
谓词完成。像这样:
X is Y + 1.
这个操作符统一的X
值设定为相同的评价表达Y+1
的值。在这种情况下,出于上面给出的相同原因,您也不能有X is X+1
:X
不能与X+1
相同,并且Prolog不允许子句内的变量“重新实例化”。所以你需要像X1 is X + 1
这样的东西。还要注意,要使is/2
正常工作,右侧表达式中的所有内容都必须预先实例化。如果右侧表达式中的任何变量没有值,您将得到一个实例化错误,或者在Turbo Prolog的情况下,表达式中的自由变量...。
因此,您需要对表达式结果使用不同的变量,并组织代码,以便如果使用is/2
,则表达式中的变量将被实例化。
我塞吉Dymchenko了解到,睿频Prolog的,不像GNU或SWI,计算表达式为=/2
。所以=
将工作在给定的问题。然而,关于实例化(或“自由变量”)的错误仍然是由我上面提到的相同问题引起的。
我试过这个但仍然没有工作总和(N,R): - P = R + N, N1 = N-1, sum(N1,P)。 – user3043278
@ user3043278查看有关'=/2'与'is/2'的答案。另请参阅关于“表达式中的自由变量”原因的描述。首先,您需要'is'而不是'='。 '='不是正确的谓词。其次,按照它们存在于你的子句中的顺序,由于实例化(自由变量)错误,“is”将失败。 – lurker
mbratch,Visual Prolog(和Turbo Prolog)是一个有趣的东西,=/2被用来代替is/2:参见http://progopedia.com/implementation/visual-prolog/ –
@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个足够大的值,执行将堆栈溢出失败。
我不明白你为什么使用X和T.我理解了总和的递归算法,但我不知道如何在Prolog中编写它。如果我的号码大于1,我将这个号码加到结果中,然后调用sum(number-1)。 – user3043278
@ user3043278:我宁愿数起来,而不是倒数。一个六个;正如他们所说,另一半是另一半。我已经添加了一个简单的倒计时版本到我的答案。还增加了一些更接近你最初的解释,为什么我采取了我做的方法。 –
既然你已经有了很多关于你的代码的建议,那就让我把代码片断(有点偏离主题)。
计数和更普遍的聚合是Prolog在与其他关系型声明性语言(读取SQL)相比较时不会发光的区域。但某些特定供应商library使其更令人愉快:
?- aggregate(sum(N),between(1,4,N),S).
S = 10.
当您运行程序时发生了什么? – lurker
你能否编辑你的代码以明确什么是评论和代码?这个文件不会按原样加载/编译。 –
@ChristianF这似乎是Visual Prolog,它使用了命名部分并允许定义'domains'部分中的数据类型。这有点不合标准。上面的代码是语法上有效的Visual Prolog代码(拼写错误的“intger”)。 – lurker