Код:
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
.