Я удалил все, что было ненужным в вашем коде, и изменил несколько вещей, и вот что я закончил:
% 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).
Теперь попробуйте программу вот так. И не удивляйтесь: вы будете не единственным, кто станет их собственным дедом! ; -)