; (или) оператор в Прологе не возвращает true, если только левая сторона не равна true, даже если правая часть оператора сама возвращает true - PullRequest
1 голос
/ 14 марта 2020

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

. Кажется, мой код должен работать в соответствии с http://www.cse.unsw.edu.au/~billw/dictionaries/prolog/or.html.

Case2 работает, когда case1 закомментирован, поэтому он должен возвращать true, но, поскольку он находится справа от оператора, это не так. (?)

Для наглядности параметры означают Person1, Person2, TypeOfCousinsTheyAre, DegreesRemovedTheyAre. Я пытаюсь написать правила, которые определяют, будут ли двое двоюродных братьев раз удалены.

Вот строка, которая использует оператор or, который не вернет true, если правая сторона true:

cousins(A, B, 1, 1) :- ( cousinsCase1(A, B, 1, 1) ; cousinsCase2(A, B, 1, 1) ).

Другие вещи, которые я пробовал:

(1) Пропуск оператора or и написание двух идентичных функций, но всякий раз, когда они вызываются, а верхняя не срабатывает, мой сбой программы.

cousins(A, B, 1, 1) :- var(FirstCousin),
                       cousin(A, FirstCousin, 1, 0),
                       parent(FirstCousin, B),
                       A \= B.

cousins(A, B, 1, 1) :-  var(P1),
                        parent(P1, A),
                        cousin(P1, B, 1, 0),
                        A \= B,
                        A \= P1,
                        B \= P1.

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

cousins(A, B, 1, 1) :- cousinsCase1(A, B, 1, 1) -> true ; cousinsCase2(A, B, 1, 1)).

Есть ли другой способ вызвать другое правило, если первое не работает?

РЕДАКТИРОВАТЬ

Чтобы получить совет ниже приведен код:

Факты:

parent(gggm, ggm). 
parent(ggm, gm).
parent(gm, m).
parent(m, self).
parent(self, d).
parent(d, gd).
parent(gggm, gga).
parent(gga, c12a).
parent(c12a, c21a).
parent(c21a, c3).
parent(ggm, ga)
parent(ga, c11a).
parent(c11a, c2).
parent(gm, a).
parent(a, c1).
parent(m, s).
parent(s, n). 
parent(n, gn).
parent(c1, c11b).
parent(c11b, c12b).
parent(c2, c21b).
parent(c21b, c22).
parent(c3, c31).
parent(c31, c32).

Другие правила, которые я написал для того, чтобы заставить работать вышеуказанные правила:

% Sibling Rule
sibling(A, B) :- parent(P, A), parent(P, B), A \= B.
% First-cousin Rule:
cousin(A, B, 1, 0) :- sibling(P1, P2), parent(P1, A), parent(P2, B).
% Second-cousin Rule:
cousin(A, B, 2, 0) :- parent(P1, A),
                      parent(P2, B),
                      parent(PP1, P1), % your grandparent
                      parent(PP2, P2), % your grand-aunt/uncle
                      sibling(PP1, PP2). % they're siblings
% 3rd-cousin and more Rule
cousin(A, B, M, 0) :- ReducedM = M - 1,
                      cousin(A, B, ReducedM, 0).

Призывы к вышеуказанным правилам: Sidenote: оба вызова работают, но проблема в том, чтобы заставить их работать без комментариев Из другого правила:

двоюродные братья (self, c11b, 1, 1).

Этот вызов соответствует первому "двоюродному брату, однажды удаленному" case и case возвращает правильный ответ true, если другой случай закомментирован.

двоюродные братья (self, c11a, 1, 1).

Этот вызов соответствует во втором случае «1-й кузен, однажды удаленный», и дело возвращает правильный ответ «истина», если другой случай закомментирован.

Ответы [ 2 ]

4 голосов
/ 14 марта 2020

Это комментарий в ответе, потому что он не будет правильно форматироваться в комментарии.

То, что большинство новичков в Прологе не осознают достаточно рано, это то, что Пролог основан на логике c (что они реализовать), и три базовых оператора logi c and, or и not являются операторами в Прологе, а именно (, ; \+). Эти операторы не понимают, кто они на самом деле.


Начиная с not, который в Прологе был not / 1 , но теперь обычно (\ +) / 1 .

?- \+ false.
true.

?- \+ true.
false.

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

?- not(true).
false.

?- not(false).
true.

Далее - and, что в Прологе равно , / 2 .

Причина, по которой многие новые пользователи Prolog не видят это как logical and, заключается в том, что , во многих других языках программирования рассматривается как разделитель операторов ( Ref ) и действует очень как , в предложении Engli sh. Вся проблема с занижением , в программировании заключается в том, что он действительно оператор и используется для стольких вещей, что программисты даже не понимают, что его почти всегда следует рассматривать как оператор, но с разными значениями (оператор перегрузка). Кроме того, поскольку , используется в качестве разделителя операторов, операторы обычно помещаются в отдельные строки, а некоторые программисты даже считают, что запятая (,) - это просто конец оператора, а точка (.) - конец строки. в предложении; это не способ думать об этих односимвольных операторах. Они операторы, и их нужно рассматривать и понимать как таковые.

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

?- true,true.
true.

?- true,false.
false.

?- false,true.
false.

?- false,false.
false.

Наконец, логично или что в Prolog равно ; / 2 или в DCG появятся как | / 2 . Использование |/2 в DCG такое же, как | в BNF .

?- true;true.
true ;
true.

?- true;false.
true ;
false.

?- false;true.
true.

?- false;false.
false.

Интересно отметить, что результаты использования или (;) в Пролог состоит в том, что они вернутся, когда истинно столько раз, сколько одно из утверждений истинно и ложно, только когда все предложения ложны. (Не уверен, что предложение является правильным словом для использования здесь). например,

?- false;false;false.
false.

?- false;false;true.
true.

?- true;false;true.
true ;
true.

?- true;true;true.
true ;
true ;
true.

Если вы не прислушались к моему предупреждению о размышлениях об операторах, когда видите их, то сколько из вас смотрели на

?- true,true.
true.

и не смотрели думаю, что в исходном коде это обычно пишется как

true,
true.

, а , выглядит как конец оператора. , - это не конец оператора, это оператор logical and. Поэтому сделайте себе одолжение и будьте очень критичны даже к одному ,, так как он имеет специфическое значение c в программировании.

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

A =
1 +
2 +
3

Это не то, как полезно видеть простое математическое выражение, но так же, как некоторые программисты смотрят на использование оператора ,.

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

Подробнее см. В разделе 1.2. Элемент управления на стр. 23 этой бумаги .


РЕДАКТИРОВАТЬ

Вам действительно необходимо использовать контрольные примеры. Вот два, чтобы вы начали.

Это делается с помощью SWI-Prolog

:- begin_tests(family_relationship).

sibling_test_case_generator(ggm ,gga ).
sibling_test_case_generator(gga ,ggm ).
sibling_test_case_generator(gm  ,ga  ).
sibling_test_case_generator(ga  ,gm  ).
sibling_test_case_generator(m   ,a   ).
sibling_test_case_generator(a   ,m   ).
sibling_test_case_generator(self,s   ).
sibling_test_case_generator(s   ,self).

test(01,[forall(sibling_test_case_generator(Person,Sibling))]) :-
    sibling(Person,Sibling).

cousin_1_0_test_case_generator(gm  ,c12a).
cousin_1_0_test_case_generator(ga  ,c12a).
cousin_1_0_test_case_generator(m   ,c11a).
cousin_1_0_test_case_generator(a   ,c11a).
cousin_1_0_test_case_generator(self,c1  ).
cousin_1_0_test_case_generator(s   ,c1  ).
cousin_1_0_test_case_generator(d   ,n   ).
cousin_1_0_test_case_generator(c12a,gm  ).
cousin_1_0_test_case_generator(c12a,ga  ).
cousin_1_0_test_case_generator(c11a,m   ).
cousin_1_0_test_case_generator(c11a,a   ).
cousin_1_0_test_case_generator(c1  ,self).
cousin_1_0_test_case_generator(c1  ,s   ).
cousin_1_0_test_case_generator(n   ,d   ).

test(02,[nondet,forall(cousin_1_0_test_case_generator(Person,Cousin))]) :-
    cousin(Person, Cousin, 1, 0).

:- end_tests(family_relationship).

РЕДАКТИРОВАТЬ

enter image description here

By! Оригинал: J Di Вектор: Мэтт Лейдхольм ( LinkTiger ) - собственная работа на основе: Cousin tree.png , Publi c Domain, Link

1 голос
/ 15 марта 2020

Это ответ.

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

parent(gggm, ggm).
parent(ggm, gm).
parent(gm, m).
parent(m, self).
parent(self, d).
parent(d, gd).
parent(gggm, gga).
parent(gga, c12a).
parent(c12a, c21a).
parent(c21a, c3).
parent(ggm, ga).
parent(ga, c11a).
parent(c11a, c2).
parent(gm, a).
parent(a, c1).
parent(m, s).
parent(s, n).
parent(n, gn).
parent(c1, c11b).
parent(c11b, c12b).
parent(c2, c21b).
parent(c21b, c22).
parent(c3, c31).
parent(c31, c32).

% Sibling Rule
sibling(A, B) :-
    parent(P, A),
    parent(P, B),
    A \= B.

% First-cousin Rule:
cousin(A, B, 1, 0) :-
    sibling(P1, P2),
    parent(P1, A),
    parent(P2, B).

% Second-cousin Rule:
cousin(A, B, 2, 0) :-
    parent(P1, A),
    parent(P2, B),
    parent(PP1, P1), % your grandparent
    parent(PP2, P2), % your grand-aunt/uncle
    sibling(PP1, PP2). % they're siblings

% 3rd-cousin and more Rule
cousin(A, B, M, 0) :-
    % ReducedM = M - 1,
    ReducedM is M - 1,
    ReducedM > 0,
    cousin(A, B, ReducedM, 0).

cousinsCase1(A, B, 1, 1) :-
    % var(FirstCousin),
    cousin(A, FirstCousin, 1, 0),
    parent(FirstCousin, B),
    A \= B.

cousinsCase2(A, B, 1, 1) :-
    % var(P1),
    parent(P1, A),
    cousin(P1, B, 1, 0),
    A \= B,
    A \= P1,
    B \= P1.

cousins(A, B, 1, 1) :-
    (
        cousinsCase1(A, B, 1, 1)
    ;
        cousinsCase2(A, B, 1, 1)
    ).

Первое изменение было, как отметил Пауло, и проверки для var / 2 были закомментированы.

Следующее изменение должно было изменить = на is.

Третье изменение, чтобы остановить бесконечный цикл, было добавить ReducedM > 0,.

Этот запрос теперь выполняется.

?- cousins(Person,Cousin,1,1).
Person = gm,
Cousin = c21a ;
Person = ga,
Cousin = c21a ;
Person = m,
Cousin = c2 ;
Person = a,
Cousin = c2 ;
Person = self,
Cousin = c11b ;
Person = s,
Cousin = c11b ;
Person = d,
Cousin = gn ;
Person = c12a,
Cousin = m ;
Person = c12a,
Cousin = a ;
Person = c12a,
Cousin = c11a ;
Person = c11a,
Cousin = self ;
Person = c11a,
Cousin = s ;
Person = c11a,
Cousin = c1 ;
Person = c1,
Cousin = d ;
Person = c1,
Cousin = n ;
Person = n,
Cousin = gd ;
Person = m,
Cousin = c12a ;
Person = self,
Cousin = c11a ;
Person = d,
Cousin = c1 ;
Person = gd,
Cousin = n ;
Person = c21a,
Cousin = gm ;
Person = c21a,
Cousin = ga ;
Person = c11a,
Cousin = c12a ;
Person = c2,
Cousin = m ;
Person = c2,
Cousin = a ;
Person = a,
Cousin = c12a ;
Person = c1,
Cousin = c11a ;
Person = s,
Cousin = c11a ;
Person = n,
Cousin = c1 ;
Person = gn,
Cousin = d ;
Person = c11b,
Cousin = self ;
Person = c11b,
Cousin = s ;
false.
...