我想写一个函数resident(房屋号,N)
(1)给我每间房子的居民人数,给出门牌号
AND
(2)如果门牌号是一个变量,则可以回溯每个门牌号的所有居民数。
给出以下以居民身份(姓,名,门牌号)的事实。
resident('Tim','Cook',1).
resident('Elisabeth','Cook',1).
resident('Thomas','Cook',1).
resident('George','Cook',1).
resident('Steve','Jobs',2).
resident('Lisa','Jobs',2).
resident('Karen','Jobs',2).
resident('Mark','Zuckerberg',3).
resident('Priscilla','Zuckerberg',3).
第二个条件应类似于:
residents(X,N).
X = 1,
N = 4,
X = 2,
N = 3,
X = 3,
N = 2.
我尝试了以下尝试。
residents(X,N):-
findall(X,resident(_,_,X),L),
length(L,N).
第一个条件满足,但是第二个条件给了我所有居民的总数,而不是每个房屋的总和。我也尝试了bagof和setof谓词,但没有帮助。非常感谢您的帮助。
答案 0 :(得分:3)
问题是findall/3
自动对自由变量(这里的名字和姓氏)进行量化,以便合并所有用于相同地址的解决方案。看一下bagof/3
(see e.g. the SWI Documentation),它可以让您手动进行量化(此处没有必要)。要查找居住在该地址的人数,列表L
还需要按人数(而不是人数本身)收集居民的姓名:
?- bagof(X-Y, resident(X,Y,Z), Zs), length(Zs, N).
Z = 1,
Zs = ['Tim'-'Cook', 'Elisabeth'-'Cook', 'Thomas'-'Cook', 'George'-'Cook'],
N = 4 ;
Z = 2,
Zs = ['Steve'-'Jobs', 'Lisa'-'Jobs', 'Karen'-'Jobs'],
N = 3 ;
Z = 3,
Zs = ['Mark'-'Zuckerberg', 'Priscilla'-'Zuckerberg'],
N = 2.
答案 1 :(得分:-4)
通常使用 bagof
和 setof
进行复杂的表象表示数据模型需要工作。
当序言谓词表示数据项时,最好将其视为数据库表。
谓词的名称与数据库表的名称相对应。
谓词的参数与数据库表中的字段相对应。
例如:如果设计和规范化数据库表,那么“居民”肯定不会存储门牌号码的值;相反,“居民”具有对“房屋”的引用,而“房屋”是其自身的实体。
:- [library('lists')] .
:- source .
:- initialization demo .
(
demo
)
:-
(
?- residents(HOUSEi,COUNTi)
)
.
(
residents(_houseI_,_countI_)
)
:-
(
house(_houseI_)
,
house_residents(house(_houseI_),_residentS_)
,
length(_residentS_,_countI_)
)
.
(
house_residents(_houseO_,_residentS_)
)
:-
(
_houseO_
,
_queryO_ = resident(_,_houseO_)
,
setof(_queryO_,_queryO_,_residentS_)
)
.
house(1) .
house(2) .
house(3) .
resident(name(first('Tim'),last('Cook')),house(1)).
resident(name(first('Elisabeth'),last('Cook')),house(1)).
resident(name(first('Thomas'),last('Cook')),house(1)).
resident(name(first('George'),last('Cook')),house(1)).
resident(name(first('Steve'),last('Jobs')),house(2)).
resident(name(first('Lisa'),last('Jobs')),house(2)).
resident(name(first('Karen'),last('Jobs')),house(2)).
resident(name(first('Mark'),last('Zuckerberg')),house(3)).
resident(name(first('Priscilla'),last('Zuckerberg')),house(3)).