Как правильно сформулировать исключение для findall / 3? - PullRequest
0 голосов
/ 14 апреля 2020

Я начал изучать Пролог и хочу получить список противников игроков с помощью findall / 3. В Обобщении я просто хочу добавить в список только противников, которые на самом деле являются игроками, кроме игрока, которого я спрашиваю сам. Как я могу сформулировать это исключение? Я знаю об отрицании как о концепции отказа, но я не уверен, нужна ли она мне здесь и как.

player(irina).
player(anton).
player(michael).

opponent(irina, anton).
opponent(irina, maria).
opponent(irina, michael).

% Only opponents who are also players should be added to the list, 
% except the player of interest itself 
opponent(X, Y) :- X \= Y, player(Y).

% the query
?- findall(O, opponent(irina,O) , OpponentList).

% the result
% only the first three results from the facts, 
% the results from the rule, a second entry of
% anton and michael are missing.
OpponentList = [anton, maria, michael].

Я действительно ожидал, что разрешение будет работать следующим образом:

opponent(irina, irina) :- irina \= irina, player(irina).
%                              false          true
%                                      false
% false, hence not added to the list

opponent(irina, anton) :- irina \= anton, player(anton).
%                              true          true
%                                     true
% true, hence added to the list

Чего мне не хватает? Большое спасибо заранее!

1 Ответ

0 голосов
/ 14 апреля 2020

Код:

player(irina).
player(anton).
player(michael).

opponent(irina, anton).
opponent(irina, maria).
opponent(irina, michael).

opponent(X, Y) :- 
   format("Called with X = ~q, Y = ~q\n",[X,Y]),
   X \= Y,     % this will fail if Y is still fresh because X and Y can be unified!
   player(Y).

opponent_mod(X, Y) :-
   format("Called with X = ~q, Y = ~q\n",[X,Y]),
   player(Y),  % this will set Y to various players  
   X \= Y.     % the test for un-unifiability of two set vars may or may not succeed 

% query helpfully as code:

q(Who,OpponentList) :- findall(O, opponent(Who,O) , OpponentList).

q_mod(Who,OpponentList) :- findall(O, opponent_mod(Who,O) , OpponentList).

% even better

q_mod_set(Who,OpponentList) :- setof(O, opponent_mod(Who,O) , OpponentList).

Запустите его:

Не ожидается:

?- q(irina,X).
Called with X = irina, Y = _19654
X = [anton, maria, michael].

Ожидается:

?- q_mod(irina,X).
Called with X = irina, Y = _20568
X = [anton, michael].

Так что же происходит в случай "не ожидается" с Who = irina:

  • findall/3 пытается собрать все значения Y так, что opponent(Who,O)
  • находит anton, maria, michal через факты
    • opponent(irina, anton).
    • opponent(irina, maria).
    • opponent(irina, michael).
  • Это также пробует правило opponent(X, Y) :- ... с X = irina (только один раз). Но тест X \= Y завершается неудачей , поскольку X ограничен значением irina, но Y все еще fre sh (полностью без ограничений). Это означает, что объединение X и Y могло бы быть успешным, если бы оно было предпринято (что и проверяется, = как таковое не означает «не равно»). Таким образом, X \= Y является ложным в этой точке вычисления. Если вы переместитесь на X \= Y после player(Y), тогда Y будет ограничено тем, что было взято из фактов player/1, и это приведет к фактическому сравнению значений X и Y.
...