Пролог: человек родной брат?
У меня возникают проблемы с пониманием того, почему мой код в прологе делает что-то, основываясь на порядке, в котором я ввел свои правила.
Вот моя база данных:
parent(tom, bob).
parent(tom, liz).
parent(mary, bob).
parent(mary, liz).
male(tom).
male(bob).
female(mary).
female(liz).
А вот и правила:
%difference(X, Y) ==> Predicate to check if two people X and Y are not the same person.
difference(X, Y) :- \==(X, Y).
father(X, Y) :- male(X), parent(X, Y), difference(X, Y).
mother(X, Y) :- female(X), parent(X, Y), difference(X, Y).
sibling(X, Y) :-
difference(X, Y),
mother(M, X), mother(M, Y),
father(F, X), father(F, Y).
Проблема в том, что когда я делаю это,
?- sibling(bob, X).
я получил
X = bob ;
X = liz ;
false.
Но когда я меняю порядок (я помещаю разницу (X, Y) в последнюю часть)
sibling(X, Y) :-
mother(M, X), mother(M, Y),
father(F, X), father(F, Y),
difference(X, Y).
и я звоню
?- sibling(bob, X).
я получил
X = liz;
false.
что я и хочу
До сих пор я видел только то, что порядок правил имеет значение при выполнении рекурсии. Поэтому я не понимаю, как Боб по-прежнему является родным братом только потому, что я поставил проверку различий первым.
Спасибо за любую помощь!
2 ответа
Это из-за того, как работает объединение. Если вы ставите разницу первым, значения X и Y еще не объединены ни с какими значениями. Рассмотрим след:
goal list: [sibling(bob, Z)]
goal: sibling(bob, Z).
X-> bob, Y -> Z
goal list: [difference(bob, Y), mother(M, bob), mother(M, Y), father(F, bob), father(F, Y).]
goal: difference(bob, Y) --SUCCESS
goal list: [mother(M, bob), mother(M, Y), father(F, bob), father(F, Y).]
goal: mother(M, bob)
...
Когда вы используете разностный вызов последним, X и Y были объединены, и различие не будет выполнено, если они имеют одинаковое значение. Тогда произойдет возврат.
Используйте функцию трассировки среды пролога, чтобы увидеть, что происходит шаг за шагом во время выполнения.
Фактическая причина вашей проблемы (\==)/2
в different/2
, Это получается просто слишком часто. Замени это dif/2
и вы получите ожидаемое поведение. dif/2
доступно во многих системах Prolog, таких как SICStus, YAP, B, SWI. Вы также можете определить безопасное приближение в ISO-Prolog следующим образом:
iso_dif(X, Y) :-
X \== Y,
( X \= Y -> true
; throw(error(instantiation_error,iso_dif/2))
).
Теперь, если аргументы будут недостаточно проработаны, вы получите сообщение об ошибке. Пролог прерывает вычисления и говорит: я понятия не имею! Что гораздо лучше, чем притворяться, у него есть идея, а у нее ее нет.
С помощью iso_dif/2
вам все равно придется поместить его в конец правила. Но на этот раз Пролог будет следить за его правильным использованием.
| ?- iso_dif(a,b).
yes
| ?- iso_dif([a,_],[b,_]).
(8 ms) yes
| ?- iso_dif([a,X],[X,b]).
yes
| ?- iso_dif([a,X],[a,X]).
no
| ?- iso_dif([a,X],[X,X]).
uncaught exception: error(instantiation_error,iso_dif/2)