我正在学习Prolog,我理解如何计算列表的总和,但我无法弄清楚如何计算数据库字段的总和。
Sample database:
tastiness(bacon,100,200,300,400,500).
tastiness(lettuce,3,5,6,7,12).
Sample output
(bacon,1500).
(lettuce,33).
答案 0 :(得分:1)
以下是如何在标准Prolog中对列表的值求和:
sumlist([], 0).
sumlist([X|Xs], Sum) :-
sumlist(Xs, SumTail),
Sum is X + SumTail.
如果您有类似
的内容bacon(100).
bacon(200).
bacon(300).
bacon(400).
bacon(500).
然后您可以使用findall
谓词。 findall
谓词的工作原理如下:如果您想要Z = [100, 200, 300, 400, 500]
(所有培根编号列表),请编写findall(X, bacon(X), Z)
。
以下是如何总结所有培根数字:
| ?- findall(X, bacon(X), AllBacon), sumlist(AllBacon, SumBacon).
AllBacon = [100,200,300,400,500]
SumBacon = 1500
yes
答案 1 :(得分:1)
作为旁注,@ aooobe提出的和计算并不是最优的,因为在一个非常大的列表中,你将用尽调用堆栈内存。
一种特殊技术是将谓词的递归调用作为谓词的最后一个元素。这样,所有前面的事情都已经计算好了,Prolog可以在进行递归调用时刷新谓词的当前上下文。在包含1M元素的列表中,这意味着您将保留1个上下文而不是最多100个。
虽然对于这个特定的练习来说这对你来说似乎并不重要,但是如果你考虑空间消耗,那么尾调用优化是使递归像迭代一样强大的原因。值得学习!
以下是Tail Call Optimization可执行的版本:
sumlist(List, Result) :-
sumlist(List, 0, Result).
sumlist([], Acc, Acc).
sumlist([Item|List], Acc, Result) :-
NewAcc is Acc + Item.
sumlist(List, NewAcc, Result).
它使用了一个在声明性编程中会遇到很多的习语:一个累加器(这里名为Acc
)。其目的是在递归期间保持结果值“直到现在”。