Пролог Backtracking findall для двух переменных - PullRequest
0 голосов
/ 30 декабря 2018

Я хочу написать функцию жителей (Housenumber, N), которая

(1) дает мне количество жителей на дом с учетом номера дома

И

(2) когда Housenumber является переменной, можно отследить все резидентские числа для каждого номера дома.

Приведены следующие факты в форме резидента (имя, фамилия, Housenumber).

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 голосов
/ 30 декабря 2018

Часто сложные махинации с 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)).
0 голосов
/ 30 декабря 2018

Проблема в том, что findall/3 автоматически определяет количество свободных переменных (здесь имя и фамилия), так что все решения для одного адреса объединяются.Взгляните на bagof/3 (см., Например, документацию SWI) , это позволяет вам определять количество вручную (что здесь не обязательно).Чтобы узнать количество людей, проживающих по адресу, в списке 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.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...