Вы были так близко.
Если бы вы выполнили запрос
nephew(X,Y)
, вы бы получили
?- nephew(X,Y).
X = pam,
Y = liz ;
X = john,
Y = liz ;
X = liz,
Y = joe ;
X = liz,
Y = tim ;
false.
, что, как вы заметили, неверно.
Однако если вы переименуете свои переменные так, чтобы их было легче понять
sibling(Child_a, Child_b) :-
parent(Parent, Child_a),
parent(Parent, Child_b),
Child_a \= Child_b.
son(Child,Parent) :-
parent(Parent, Child),
male(Child).
nephew(Parent, Child_a) :-
sibling(Child_a, Child_b),
son(Child_b, Parent).
вы увидите, что sibling / 2 и son / 2 верны и должны увидеть вашу проблему с племянником / 2.
Когда переименовываете переменные, начинайте с фактов и работайте в обратном направлении, не начинайте с заголовка предложения и работайте вниз.
Еще один способ, который помогает выяснить проблемы с несколькими утверждениямиПредикаты должны запускать их части как отдельные запросы, например
?- sibling(Parent,Aunt_uncle),son(Nephew,Parent).
Parent = liz,
Aunt_uncle = bob,
Nephew = joe ;
Parent = liz,
Aunt_uncle = bob,
Nephew = tim ;
Parent = pat,
Aunt_uncle = ann,
Nephew = jim ;
false.
Хотя этот запрос дает больше информации, чем необходимо, правильные значения содержатся в результатах.Поместив это в предикат и вернув только нужные значения, это все, что осталось, чтобы этот запрос работал как нужно.
Правильный ответ для племянника / 2:
nephew(Nephew,Aunt_uncle) :-
sibling(Parent,Aunt_uncle),
son(Nephew,Parent).
Пример выполнения:
?- nephew(Nephew,Aunt_uncle).
Nephew = jim,
Aunt_uncle = ann ;
Nephew = joe,
Aunt_uncle = bob ;
Nephew = tim,
Aunt_uncle = bob ;
false.
При написании кода рекомендуется также создавать тестовые случаи.
Если вы используете SWI-Prolog, тогда вы можете использовать следующие тестовые случаи.
:- begin_tests(family).
% example of single test case
test(001) :-
sibling(bob,liz).
test(002) :-
son(tim,liz).
test(003,[nondet]) :-
nephew(tim,bob).
% example of test cases that test multiple variations for one predicate
sibling_test_case(bob,liz).
sibling_test_case(liz,bob).
sibling_test_case(ann,pat).
sibling_test_case(pat,ann).
sibling_test_case(joe,tim).
sibling_test_case(tim,joe).
test(004, [forall(sibling_test_case(Child_a,Child_b))]) :-
sibling(Child_a,Child_b).
son_test_case(bob,pam).
son_test_case(bob,john).
son_test_case(jim,pat).
son_test_case(joe,liz).
son_test_case(tim,liz).
test(005, [forall(son_test_case(Child,Parent)),nondet]) :-
son(Child,Parent).
nephew_test_case(joe,bob).
nephew_test_case(tim,bob).
nephew_test_case(jim,ann).
test(006, [forall(nephew_test_case(Nephew,Aunt_uncle)),nondet]) :-
nephew(Nephew,Aunt_uncle).
:- end_tests(family).
Они запускаются с run_tests.
?- run_tests.
% PL-Unit: family ................. done
% All 17 tests passed
true.
См .: Пролог-модульные тесты