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.
我是 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.