Prolog 为求和查询返回 false

Prolog returning false for summation query

我是 Prolog 的新手,因为我刚刚开始学习和编写我自己的一小组数据库规则。使用我自己的数据库规则 .pl 文件,我在使用这些规则输入 Prolog 的查询时遇到了一个小问题。下面显示了我的小型规则数据库:

staff(andy,18235,3).
staff(beth,19874,4).
staff(andy,18235,5).
staff(carl,16789,2).
staff(earl,34567,9).

sum([], 0).
sum([H|T], X) :-
   sum(T, X1),
   X is X1 + H.

getincome(Name, Income) :-
   findall(Income,staff(Name,_,Income),Member),
   sum(Member, Income).

如您所见,我编写了一条规则来计算特定员工的总收入。这工作得很好,当我输入时:

?- getincome(andy, X).

程序总是returns:

X = 8

它应该做的,但是每当我输入:

?- getincome(andy, 8).

这总是 returns 错误,而它应该是正确的。

然而当我也输入:

?- getincome(andy, 3).

这 returns 正确,因为已经在数据库中。

我只是想知道,我如何修改此规则,以便它可以为任何给定员工(尤其是 Andy)输入的正确总和值输出 true,而不是给定数据库中已有的值?

忽略我上面的问题!

感谢您的帮助 'false'。我还有另一个问题,这次是计算和显示每个成员的收入总和。我已经修改了我的规则,为了显示这个,如下:

getincome(Name, I) :- staff(Name, _, _ ), findall(Income,staff(Name,_,Income),Member), sum(Member, I).

每当我输入查询时:

?- getincome(X, Y).

我不断收到员工(当然最著名的是安迪)的重复结果,如下所示:

X = andy,
Y = 8 ;
X = beth,
Y = 4 ;
X = andy,
Y = 8 ;
X = carl,
Y = 2 ;
X = earl,
Y = 9.

我可以做哪些更改来避免这些重复?

一种方法是使用bagof收集每组收入:

person_income(Name, Income) :-
    bagof(I, X^staff(Name,X,I), Incomes),  % Incomes for a given name
    sumlist(Incomes, Income).           % Sum the incomes

结果:

| ?- person_income(Name, Income).

Income = 8
Name = andy ? a

Income = 4
Name = beth

Income = 2
Name = carl

Income = 9
Name = earl

yes
| ?- person_income(andy, Income).

Income = 8

yes
| ?- person_income(Name, 8).

Name = andy ? a

no
| ?-

我将其命名为 person_income 是为了强调这是一个人与其收入之间的关系,而不是 getincome 这更像是一个命令式的概念,并没有真正反映出你可以对关系做的不仅仅是 "get the income"。另外,我在这里使用 SWI Prolog 的 sumlist/2。 GNU Prolog 有 sum_list/2。正如@CappeliC 在他的回答中指出的那样,SWI Prolog 有一个方便的 aggregate 谓词来进行这样的操作。

library(aggregate) 提供了一个干净的界面来解决这类问题:

?- aggregate(sum(S), K^staff(E,K,S), I).
E = andy,
I = 8 ;
E = beth,
I = 4 ;
E = carl,
I = 2 ;
E = earl,
I = 9.