2

Я начал изучать Пролог недавно и столкнулся с одной странной проблемой. Здесь вы можете увидеть пример кода (я использую SWI-Prolog 7.2.3), который дает дерево отношений и мое решение из 2 задач.Порядок целей (правил) в Правилах Пролога

/* File: ancestors.pl 
Author: Dave Robertson 
Purpose: Relationships in a family tree 

Suppose we have a family tree like this : 

alan andrea bruce betty  eddie elsie fred freda 
|  |  |  |   |  |  |  | 
|_____|  |_____|   |_____|  |_____| 
    |    |    |    | 
    clive  clarissa   greg   greta 
    | |__________|___|    |    | 
    |__________|__|     |_____________| 
      | |       | 
     dave doris      henry 

which is defined in Prolog by the following 3 sets of predicates: 

*/ 

% parent(Parent, Child). 
% Parent is the parent of Child. 

parent(alan, clive). 
parent(andrea, clive). 
parent(bruce, clarissa). 
parent(betty, clarissa). 
parent(clive, dave). 
parent(clarissa, dave). 
parent(clive, doris). 
parent(clarissa, doris). 
parent(eddie, greg). 
parent(elsie, greg). 
parent(fred, greta). 
parent(freda, greta). 
parent(greg, henry). 
parent(greta, henry). 

%% PROBLEM 1 
%% How do you find out if someone is the ancestor of someone else ? 
ancestor(X,Y) :- parent(X,Y). 
ancestor(X,Y) :- parent(X,Z), ancestor(Z,Y). 

%% PROBLEM 3 
%% How do you know if someone is related to someone else ? 
relative(X,Y) :- ancestor(X,Y). 
relative(X,Y) :- ancestor(Y,X). 
relative(X,Y) :- ancestor(Z,X), ancestor(Z,Y), X\==Y. 

Когда я хочу, чтобы родственники Дейва я:

relative(dave,X). 
X = clive ; 
X = clarissa ; 
X = alan ; 
X = andrea ; 
X = bruce ; 
X = betty ; 
X = doris ; 
X = doris ; 
X = clive ; 
X = doris ; 
X = clive ; 
X = doris ; 
X = clarissa ; 
X = doris ; 
X = clarissa ; 
X = doris ; 
false. 

И тогда я изменю свое определение относительного следующим способом:

relative(X,Y) :- ancestor(X,Y). 
relative(X,Y) :- ancestor(Y,X). 
relative(X,Y) :- X\==Y, ancestor(Z,X), ancestor(Z,Y). 

Я просто изменить порядок целей в последнем заявлении. А теперь у меня есть следующий вывод:

relative(dave,X). 

X = clive ; 
X = clarissa ; 
X = alan ; 
X = andrea ; 
X = bruce ; 
X = betty ; 
X = dave ; 
X = doris ; 
X = dave ; 
X = doris ; 
X = clive ; 
X = dave ; 
X = doris ; 
X = clive ; 
X = dave ; 
X = doris ; 
X = clarissa ; 
X = dave ; 
X = doris ; 
X = clarissa ; 
X = dave ; 
X = doris ; 
false. 

Я вижу Дэйва на выходе! Как это произошло? Я написал, что X \ == Y ... Может ли кто-нибудь дать мне хорошее объяснение этому?

И еще один вопрос. Как заставить мою программу не писать одни и те же ответы?

Спасибо!

ответ

3

(\==)/2 не является чистым отношением и может быть понят только оперативно. Если вы используете его, обмениваясь порядок целей может дать декларативно неправильные результаты:

 
?- X \== Y, X = Y. 
X = Y. 

Пожалуйста, используйте dif/2 вместо для чистого и полностью декларативно к государственной неэквивалентности терминов.

 
?- dif(X, Y), X = Y. 
false. 

См. для получения дополнительной информации.

+1

ПК бьет смартфон. Опять :) – repeat

2

Особенно, как новичок, попробуйте воздерживаться от использования нечистых конструкций и perserve !

Как? Используйте !

Вместо X \== Y просто напишите dif(X, Y).

+1

Спасибо, это работает! Насколько я понимаю, использование «чистых» функций более ясное, но иногда менее эффективное, я прав? –

+2

@ ИльяМурадьян. В двух словах: да! Какой смысл быть быстрым, но неправильным? – repeat

+1

Не использовать, конечно. Я просто хотел понять, в чем цель нечистых черт :) –

1

Пролог является программирование язык, основанный на определенном resolution method, а проблема, которую вы описали, только что: проблема (ну, я бы назвал это ошибка) в вашей программе. Порядок статей и целей : как вы управляете своим алгоритмом : последовательность шагов с определенными эффектами на ваше представление. Тогда знание о таких эффектах ИМХО неизбежно, и - я думаю - замена (\==)/2 на dif/2 не облегчит вашу жизнь, когда вы попытаетесь скомпоновать что-то более сложное. По крайней мере, по моему опыту, я столкнулся с дополнительными трудностями, когда мне пришлось моделировать и отлаживать мой код.

(\ ==)/2 предназначен для облегчения метапрограммирования, когда вам нужно сравнить переменные для идентификации. Таким образом, это довольно сложная функция, не требуемая для вашей программы.Но (возможно, потому, что он настолько похож на C/C++/Java-операторы), легко недооценивать его цель.

Для вашего использования (\=)/2 будет служить лучше, но опять же, это требует, для простого использования, что оба аргумента инстанцирован. Это верно, зависит от в целом «граф вывода» в результате фактического вызова целей - оперативной семантики. Как правило, это не просто (или даже возможно, я думаю), чтобы определить, безопасен ли предикат для вызова с определенным шаблоном. Рассмотрим этот контрпример я получил в качестве комментария около моего naive assertion - добавление/3, чистый Пролог библиотека предикат является безопасным для всех моделей instatiation:

?- append(Xs,[a],Xs). 

Чтобы избежать дублирования, и перечислять результат, я хотел бы использовать setof/3

?- setof(R, relative(dave, R), Relatives), maplist(writeln, Relatives). 
+0

Благодарим за подробный ответ! Мне кажется, что я (почти) осознал разницу между dif и (\ ==) в данном конкретном случае. Как я понял, X \ == Y просто сокращает неправильные результаты, но только если он находится в конце (если эти результаты уже были оценены). И если он находится в начале, (\ ==) ничего не делает, потому что переменные X и Y не создаются. Я прав? Можете ли вы порекомендовать мне книгу/статью/сайт, описывающий, КАК ЭТО РАБОТАЕТ. Я до сих пор не понимаю, как делает Prolog ... И спасибо за ваш метод избежания дубликатов) –

+0

Дело в том, что \ == используется для проверки переменных * status *, not (only) values , Объяснение в нескольких словах выходит за рамки моих возможностей. Пример, отправленный @mat, - это самый простой код, который вы можете попытаться понять: порядок целей очень важен – CapelliC

 Смежные вопросы

  • Нет связанных вопросов^_^