两个变量的Prolog回溯findall

时间:2018-12-30 00:39:35

标签: prolog

我想写一个函数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谓词,但没有帮助。非常感谢您的帮助。

2 个答案:

答案 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)).