Пролог - симметричные предикаты - PullRequest
3 голосов
/ 27 апреля 2009

Мне нужно смоделировать генеалогическое древо в прологе. И у меня есть проблема симметричных предикатов. Факты:

parent(x,y).
male(x).
female(y).
age(x, number).

Правила:

blood_relation вызывает у меня головную боль. вот что я сделал:

blood_relation(X,Y):-ancestor(X,Y).
blood_relation(X,Y):-uncle(X,Y);brother(X,Y);sister(X,Y);(mother(Z,Y),sister(X,Z));(father(Z,Y),sister(X,Z));(father(Z,Y),brother(X,Z)).
blood_relation(X,Y):-uncle(X,Z),blood_relation(Z,Y).

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

blood_relation(johns_father, joh):yes 
blood_relation(john,johns_father): no

так что ... есть способ это исправить. И мне нужен запрос: все пары, которые не находятся в blood_relation ..

Обновление:

Какими отношениями должно удовлетворять первое утверждение? blood_relation (X, Y): - blood_relation (X, Y)

.

извините .. это плохая копия / вставка .. это

blood_relation(X,Y):-ancestor(X,Y).

Исправлено выше.

вот другие правила:

father(X,Y):-parent(X,Y),male(X).  
mother(X,Y):-parent(X,Y),female(X).  
brother(X,Y):-parent(Z,X),parent(Z,Y),male(X).  
sister(X,Y):-parent(Z,X),parent(Z,Y),female(X).  
grandFather(X,Y):-parent(Z,Y),parent(X,Z),male(X).  
grandMother(X,Y):-parent(Z,Y),parent(X,Z),female(X).  
uncle(X,Y):-mother(Z,Y),brother(X,Z).  
ancestor(X,Y):-ancestor(X,Y).  
ancestor(X,Y):-parent(X,Z),ancestor(Z,Y).

Брат матери в определении дяди. Это немного странно. У меня есть правила, которые мне нужно реализовать, и я не знаю, как я могу реализовать правила, кроме этого. Я просто запутался.

Есть идеи, как сделать blood_relation симметричным? И not_blood_relation - это новое правило. И мне нужен запрос. Этот действительно причиняет мне головную боль. Может быть, потому что отношение написано как дерьмо.

И больше нет фактов. Это все. Все правила и все факты.

query .. not(blood_relation(X,Y)) не работает, и я действительно не знаю почему. Например, запрос:

age(X,Y), Y>18,  
not(parent(X,Z)),write(X),nl,fail.

работает просто отлично

Ответы [ 3 ]

8 голосов
/ 30 апреля 2009

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

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

friends(1,2).
friends(5,2).
friends(7,4).

Сначала вы думаете, что правило типа "friends(A,B) :- friends(B,A)." исправит ситуацию, но это приводит вас к бесконечной рекурсии, потому что она говорит прологу, что если он просто поменяет аргумент еще раз, он может просто сработать. Существует предикат под названием «@</2», который сообщает вам, стоит ли один термин (даже переменная) перед другим в «стандартном порядке терминов». Технический смысл здесь не так важен, но нас волнует то, что для двух разных терминов это верно только для одного их порядка. Мы можем использовать это, чтобы сломать бесконечную рекурсию!

Это единственное правило позаботится о том, чтобы сделать "friend/2" симметричным.

friends(A,B) :- A @< B, friends(B,A).

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

Рассмотрите промышленно-прочное решение:

friended(1,2).
friended(5,2).
friended(7,4).

friends(A,B) :- friended(A,B).
friends(A,B) :- friended(B,A).

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

-

Что касается поиска пар, которые не не имеют определенного свойства, обязательно включайте в свой правило какой-то предикат для обеспечения контекста, когда вы используете отрицание для поиска реальных личностей.

potential_enemies(A,B) :- user(A), user(B), \+ friends(A,B).
1 голос
/ 27 апреля 2009

Немного похоже на домашнюю работу, не правда ли ...

Одна хитрость, о которой большинство начинающих прологов не задумывается, - это сопоставление с образцом списка. Представьте себе дерево, похожее на [a1, [[a2], [b2, [[e3], [f3]]], [c2]]], как в <tree> = [root, [<tree1>, <tree2>, ...]]:

%Y is immediate child of X?
child(X,Y,[X|S]) :- member([Y|_],S).

%pick one tree in S and check
child(X,Y,[X|S]) :- member([Z|SS],S),child(Z,Y,[Z|SS]).

%X and Y end up with same root?
sib(X,Y,[R|T]) :- child(R,X,[R|T]), child(R,Y,[R|T]).

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

0 голосов
/ 27 апреля 2009

Каким отношениям должно удовлетворять первое утверждение?

blood_relation(X,Y):-blood_relation(X,Y).

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

Вы действительно должны опубликовать больше фактов и определение дяди / 2, и есть ли причина, по которой вы не соответствуете брату матери, только ее сестре? У вас есть много других вопросов для работы: -).

Для всего, что не является кровным родством, попробуйте это:

not_blood_relation(X, Y) :- blood_relation(X, Y), !, fail.
not_blood_relation(X, Y).

И спросите себя, почему это работает!

...