[英]Sum of elements in list in Prolog needs little explanation
我是prolog编程的初学者,我希望你谦虚并帮助我解决这个困惑
我在prolog中计算总和面临一个问题,我有答案,但对我来说并不是那么清楚。 答案是:
list_sum([], 0).
list_sum([Head | Tail], Total) :-
list_sum(Tail, Sum1),
Total = Head + Sum1.
我不明白的是什么是Sum1
以及程序如何按步骤工作
它首先检查第一个条件list_sum([], 0).
如果条件不满足,它会将列表分为Head
和Tail
两部分吗?
我希望你接受一个小小的初学者并给他一些时间来纠正他的困惑。
谢谢你们
你的程序中有一个小错误 - 行Total = Head + Sum
意味着Total
是一个结构+
有两个参数。 你大概的意思is
代替=
意思算术评估。 但最好的是使用#=
代替。
在你的问题中,你问的是该程序将做什么 。 这在面向命令(“命令式”)语言中是一个非常合理的问题,因为你可以从程序中获得的唯一含义是它的逐步操作。 但在Prolog中,事情有点不同。 您仍然可以尝试逐步思考,但迟早您会意识到事情会变得非常复杂,仅仅因为Prolog没有一个控制流,而是两个同时被调用(AND-和OR-控制)。 甚至“数据结构”也不同......
但是有一种方法可以阅读Prolog程序,它在命令式语言中没有对应程序:您可以将程序理解为参数之间的关系。 通过这种方式,您可以专注于关系的样子而不是程序方面。 毕竟,如果描述的关系是错误的,那么询问程序如何执行此操作毫无意义。
那么让我来重温你的程序:
:- use_module(library(clpfd)).
list_sum([], 0).
list_sum([E|Es], S) :-
S #= E+T,
list_sum(Es, T).
它首先检查第一个条件list_sum([],0)。 如果条件不满足,它会将列表分为H和T两部分吗?
你的问题意味着有一个单一的控制流程(“虽然这是一个典型的构造,暗示它”)。 但它也可能有所不同。 考虑查询:
?- list_sum(Xs,0).
Xs = [] ;
Xs = [0] ;
Xs = [_G1710, _G1713],
_G1710+_G1713#=0 ...
在这里,我们询问存在哪些列表,其总和为0 。 现在,你的“同时”不再有意义。
我们得到的答案是:空列表; 列表0
; 一个两元素列表,其中元素之和为0; 等等...
理解这些程序的最好方法是将它们理解为如下关系:
list_sum([], 0
: 空列表的总和为0 。
现在,规则在箭头方向上读得最好:-
从右到左:
list_sum(Es, T).
:*提供Es
是一个总和T
和...的列表
S #= E+T
:...... S
是E
加T
...
:-
......然后我们可以得出结论......
list_sum([E|Es], S)
: S
是列表[E|Es]
的总和。
通过这种方式,可以理解这些事情,而无需过多地参考程序细节。 还有更多的东西,比如理解终止,看看故障切片 。
这是经典的递归方法 - 您需要熟悉它才能理解Prolog。
您的规则有两个子句 - 一个用于空列表,另一个用于非空子句。 空列表子句表示空列表的元素总和为零(这是完全合理的)。 这被称为“递归的基本情况”。 每个终止递归规则都必须具有基本案例。
第二个条款有点复杂。 它粗略地说:“计算非空列表中元素的总和,首先砍掉初始元素,然后计算得到的较短列表中元素的总和。调用求和Sum1
。现在通过添加计算Total
初始元素的值为Sum1
的值。
第二个子句递归地将列表分解为一系列较短的列表,直到它们到达空列表。 此时第一个子句进入,提供空列表的总和。
考虑这个例子:
list_sum([12, 34, 56], X)
list_sum([34, 56], <unknown-1>)
list_sum([56], <unknown-2>)
list_sum([], 0) ---> succeeds with Total bound to 0
<unknown-2> becomes 0 + 56 ---> succeeds with Total bound to 56
<unknown-1> becomes 0 + 56 + 34 ---> succeeds with Total bound to 90
X becomes 0 + 56 + 34 + 12 ---> succeeds with X bound to 102
这是有效的,因为递归链中的每个调用级别都为Sum1
获取自己的变量。 这些值开始无限制,但是一旦递归调用链“触底”, Sum1
开始获得由每个先前级别计算的值。 最终,调用链达到顶层,将最终结果绑定到调用者传递的变量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.