如何正确地为 findall/3 制定例外?
How to formulate an exception for findall/3 correctly?
我开始学习 Prolog,我想获得 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
我错过了什么?
非常感谢!
代码:
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].
那么 "not expected" 情况下 Who
= irina
会发生什么:
findall/3
尝试收集满足 opponent(Who,O)
的所有值 Y
- 通过事实找到
anton
、maria
、michal
opponent(irina, anton).
opponent(irina, maria).
opponent(irina, michael).
- 它还会尝试规则
opponent(X, Y) :- ...
和 X
= irina
(仅一次)。但是测试 X \= Y
失败 因为 X
已经被约束为 irina
但 Y
仍然是新鲜的(完全不受约束)。这意味着如果尝试 X
和 Y
的统一可能会成功(这是正在测试的内容,=
并不意味着 "is not equal")。所以 X \= Y
在这个计算点是错误的。如果您将 X \= Y
移到 player(Y)
之后,那么 Y
将被限制为从 player/1
事实中获取的任何内容,这将简化为值的实际比较X
和 Y
.
我开始学习 Prolog,我想获得 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
我错过了什么? 非常感谢!
代码:
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].
那么 "not expected" 情况下 Who
= irina
会发生什么:
findall/3
尝试收集满足opponent(Who,O)
的所有值 Y
- 通过事实找到
anton
、maria
、michal
opponent(irina, anton).
opponent(irina, maria).
opponent(irina, michael).
- 它还会尝试规则
opponent(X, Y) :- ...
和X
=irina
(仅一次)。但是测试X \= Y
失败 因为X
已经被约束为irina
但Y
仍然是新鲜的(完全不受约束)。这意味着如果尝试X
和Y
的统一可能会成功(这是正在测试的内容,=
并不意味着 "is not equal")。所以X \= Y
在这个计算点是错误的。如果您将X \= Y
移到player(Y)
之后,那么Y
将被限制为从player/1
事实中获取的任何内容,这将简化为值的实际比较X
和Y
.