Как я могу реализовать «Я - мой дедушка» в Прологе? - PullRequest
10 голосов
/ 16 сентября 2009

Следующая история взята из работы Н. Вирта (1976). Алгоритмы + структуры данных = Программы.

Я женился на вдове (назовем ее W) у кого была взрослая дочь D). Мой отец (F), который посетил нас довольно часто влюблялся в мой падчерица и вышла за нее замуж. Следовательно, мой отец стал моим зятем и мой падчерица стала моей мамой. Немного Через несколько месяцев моя жена родила сын (S1), который стал зять моего отца, а также как мой дядя Эта жена моего отца, то есть моя падчерица тоже имела сын (S2).

Я пытаюсь смоделировать эти отношения в прологе, чтобы в итоге я смог набрать:

| ?- grandfather(i,i).

И мне дадут «Да» или «Нет» в зависимости от того, являюсь ли я моим собственным дедушкой.

Вот код, который я написал (grandpa.pl):

aunt(X,Y):-
    sibling(X,Z),
    parent(Z,Y),
    female(X).

brother(X,Y):-
    sibling(X,Y),
    male(X).

brother_in_law(X,Y):-
    child(X,Z),
    married(Z,W),
    parent(W,Y),
    not(sibling(X,Y)),
    male(X).

brother_in_law(s1,f).

child(X,Y):-
    parent(Y,X).

daughter(X,Y):-
    parent(Y,X),
    child(X,Y),
    female(X).

daughter(d,w).

father(X,Y):-
    parent(X,Y),
    male(X).

father(f,i).

father_in_law(X,Y):-
    child(X,Z),
    married(Y,Z),
    not(child(X,Y)),
    male(X).

grandparent(X,Y):-
    parent(X,Z),
    parent(Z,Y).

grandmother(X,Y):-
    grandparent(X,Y),
    female(X).

grandfather(X,Y):-
    grandparent(X,Y),
    male(X).

grandchild(X,Y):-
    child(X,Z),
    child(Z,Y).

married(X,Y):-
    wife(X,Y),
    female(X).

married(X,Y):-
    husband(X,Y),
    male(X).

married(i,w).
married(f,d).

mother(X,Y):-
    parent(X,Y),
    female(X).

parent(X,Y):-
    child(Y,X).

sibling(X,Y):-
    parent(Z,X),
    parent(Z,Y).

sister(X,Y):-
    sibling(X,Y),
    female(X).

son(X,Y):-
    parent(Y,X),
    male(X).

son(s1,w).
son(s2,d).

son_in_law(X,Y):-
    child(X,Z),
    not(child(X,Y)),
    married(Z,Y),
    male(X).

son_in_law(f,i).

step_daughter(X,Y):-
    child(X,Z),
    married(Z,Y),
    not(child(X,Y)),
    female(X).

step_daughter(d,i).

step_parent(X,Y):-
    married(X,Z),
    parent(Z,Y),
    not(parent(X,Y)).

step_father(X,Y):-
    step_parent(X,Y),
    male(X).

step_mother(X,Y):-
    step_parent(X,Y),
    female(X).

step_mother(d,i).

uncle(X,Y):-
    sibling(X,Z),
    parent(Z,Y),
    male(X).

uncle(s1,i).

Прямо сейчас у меня много проблем с циклическими определениями, поэтому при выполнении запроса у меня возникают бесконечные циклы: grandfather (i, i).

Например, у меня есть:

(1 мс) да {трассировка} | ? - дед (я, я). 1 1 Звоните: дедушка (я, я)?
2 2 Звоните: дедушка (я, я)?
3 3 Call: parent (i, _103)?
4 4 Звоните: ребенок (_127, я)?
5 5 Звоните: родитель (я, _151)?
6 6 Звоните: ребенок (_175, я)?
7 7 Звоните: родитель (я, _199)?
8 8 Звоните: ребенок (_223, я)?
9 9 Звоните: родитель (я, _247)?
10 10 Звоните: ребенок (_271, я)?
11 11 Call: parent (i, _295)?
12 12 Звоните: ребенок (_319, я)?
13 13 Call: parent (i, _343)?
14 14 Звоните: ребенок (_367, я)?
15 15 Вызов: родитель (я, _391)?
...

Это потому, что child определяет себя как имеющего родителя, а parent определяет себя как имеющего child (как вы увидите в приведенных выше предикатах, которые я разместил).

Может ли кто-нибудь помочь мне переопределить мои предикаты для этих отношений, чтобы я мог определить, являюсь ли я моим собственным дедушкой?

Ответы [ 4 ]

6 голосов
/ 21 февраля 2013

Я удалил все, что было ненужным в вашем коде, и изменил несколько вещей, и вот что я закончил:

% married(Husband, Wife)
married(i,w).
married(f,d).

Можно предположить, что married(X,Y) :- married(Y,X), но это приводит к неприятным круговым доказательствам, поэтому мы просто поставим мужа на первое место по соглашению.

По поводу родительства возникает аналогичная проблема. Нам нужно считать приемных родителей настоящими родителями, потому что от этого зависит загадка. Мы знаем, что ты никогда не сможешь быть своим собственным биологическим предком!

Однако, parent(X,Y) :- parent(Z,Y), married(X,Z) сталкивается с теми же проблемами, поэтому я просто сделал bio_parent, обозначающий биологическое родительство.

bio_parent(f,i).
bio_parent(w,d).
bio_parent(w,s1).
bio_parent(i,s1).
bio_parent(d,s2).
bio_parent(f,s2).

Обратите внимание, что мы должны быть откровенными в отношении обоих родителей, поскольку нет никакого способа сделать вывод о биологическом родительстве из брака! Кроме того, ваш способ спецификации был проблематичным. У вас было что-то вроде:

son(X,Y) :- child(X,Y), male(X).
son(a,b).

Однако из этих правил Пролог не может сделать вывод child(a,b), поэтому вы оказались с сыновьями, которые не были детьми! Это происходило несколько раз в вашем коде. Если вы выводите b из a, всегда указывайте a как факт! На первый взгляд, это может показаться недостатком Пролога, но это не так. Помните, что каждое предложение является лишь одним из способов доказательства определенного предиката. В приведенном выше примере вы заявили, что каждый ребенок мужского пола является сыном, а также a точно так же, как и сын b. Нигде не сказано, что быть ребенком мужского пола - это единственный способ, которым кто-то может быть сыном, хотя a может быть только исключением.

Следующий является немного многословным, так как наше определение married заставляет нас относиться к отчимам отдельно от мачех. Мы объединяем их с приемными родителями хотя сразу.

step_father(X,Y) :- married(X,Z),bio_parent(Z,Y),\+bio_parent(X,Y).
step_mother(X,Y) :- married(Z,X),bio_parent(Z,Y),\+bio_parent(X,Y).
step_parent(X,Y) :- step_father(X,Y).
step_parent(X,Y) :- step_mother(X,Y).

Как я уже говорил выше, мы должны рассматривать приемных родителей как родителей!

parent(X,Y) :- step_parent(X,Y).
parent(X,Y) :- bio_parent(X,Y).

grandparent(X,Y):-
    parent(X,Z),
    parent(Z,Y).

В вашем коде были и другие ошибки, которые я исправил, я просто покажу вам несколько примеров, чтобы вы могли извлечь из них

.

Во-первых, здесь вы говорите, что женщины женаты, а мужья женаты. Таким образом, жены мужского пола не были бы замужем. Должно быть, наоборот, женатых женщин называют женами!

% wrong:
%
% married(X,Y):-
%    wife(X,Y),
%    female(X).
%
% married(X,Y):-
%    husband(X,Y),
%    male(X).
% 
% right:
% wife(X,Y) :- married(Y,X). % according to our new definition of 'married'
% husband(X,Y) :- married(X,Y).

Здесь я добавил последнюю строку, так как вы обычно не считаете себя своим родным братом:

% sibling(X,Y):-
%    parent(Z,X),
%    parent(Z,Y),
%    X \= Y. % added this

Эти последние два снова являются фактами неверного предиката. Вы в основном отменяете Пролог удержание с ними. Они должны быть вычтены, а не указаны как факты!

% son_in_law(f,i).
% step_mother(d,i).

Теперь попробуйте программу вот так. И не удивляйтесь: вы будете не единственным, кто станет их собственным дедом! ; -)

4 голосов
/ 16 сентября 2009

Мой курс по прологу был давным-давно, но как насчет удаления

parent(X,Y):-
   child(Y,X).

и просто заменить любое использование parent(A,B) на child(B,A)? Вы по-прежнему можете добавлять факты о родителях, потому что обратное правило все еще доступно - вы также можете удалить это, но в этом случае вы больше не можете использовать какие-либо факты о родителях, и вам придется записывать все свои факты как дети (a, b) а также.

То же самое, не так ли?

2 голосов
/ 16 сентября 2009

Обратите внимание, что мои знания Пролога старые (и никогда не такие глубокие) ...

Я думаю, вам нужно сделать родителя (или ребенка) первичным (не зависящим от других отношений).

child(X,Y):-
    parent(Y,X).

parent(X,Y):-
    child(Y,X).

это то, что, вероятно, вызывает петли.

0 голосов
/ 12 августа 2017

Вот факты и правила

couples(i,w).
mother_of(w,d).
father_of(f,i).
couples(f,d).
son_in_law(f,i).
mother_of(d,i).
mother_of(w,s1).
mother_of(d,s2).
grand(F,C):- son_in_law(F,C),couples(H,D),mother_of(D,C).
grand(F,C):- father_of(F,D),father_of(D,C).

запрос

?-grand(i,i).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...