2009-09-15 3 views
9

Следующая история из книги Н. Вирта (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). 

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

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

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

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

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

+0

Хех, я на самом деле должен был сделать это для моего класса AI. Интересно, есть ли у меня код ... Я посмотрю, когда вернусь домой. Я помню, что это тоже больно моему мозгу. –

+5

Они используют Пролог в Западной Виргине? ;-) –

+0

@ T.E.D .: Shh! TheTXI услышит вас! –

ответ

3

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

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

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

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

1

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

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

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

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

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

5

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

% 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 как факт! На первый взгляд это может показаться недостатком Prolog, но это не так. Помните, что каждое предложение - это всего лишь один способ доказательства определенного предиката. В приведенном выше примере вы заявили, что каждый ребенок-мужчина является сыном, а также 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 

Те последние два факты о неправильном предиката снова. Вы в основном переоцениваете вывод Prolog's с ними. Они должны быть вычтены, а не указаны как факты!

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

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

0
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).