数据库中的Prolog求和字段

时间:2012-03-20 19:11:17

标签: prolog

我正在学习Prolog,我理解如何计算列表的总和,但我无法弄清楚如何计算数据库字段的总和。

Sample database:

tastiness(bacon,100,200,300,400,500).
tastiness(lettuce,3,5,6,7,12).

Sample output
(bacon,1500).
(lettuce,33).

2 个答案:

答案 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)。其目的是在递归期间保持结果值“直到现在”。