序言中的等价关系
Equivalence relation in prolog
我想在我的 Prolog 代码中实现一个简单的 当且仅当 关系。这是我想要的一个简单示例:
?- a_iff_b(a, b).
true.
?- a_iff_b(x, x).
true.
?- a_iff_b(a, x).
false.
?- a_iff_b(x, b).
false.
你明白了——如果第一个参数是 a
而第二个参数是 b
或者如果第一个参数既不是 a
也不是第二个b
。我希望这是有道理的。从数学上讲,X = a <==> Y = b
.
这是我的尝试:
a_iff_b(X, Y) :-
X = a, Y = b;
X \= a, Y \= b.
但是这段代码引入了一个选择点:
?- a_iff_b(a, b).
true ;
false.
为什么?好像是下面的作品,我的意思是没有介绍选择点:
a_iff_b(X, Y) :- (X = a -> Y = b; Y \= b).
但是,我发现这有点可读性差,特别是因为在我的实际谓词中,等价的两侧更复杂(它们也是谓词)。
您的代码引入了一个选择点,因为它包含由 ;
运算符引入的选择。您可能会认为这是一个“逻辑或”运算符,在某种程度上它是非正式的。但在程序上它是一个“在这里引入一个选择点,并且在回溯时,也探索第二个分支”的操作符。
一个足够强大的 Prolog Compiler™ 确实能够识别出这里的两个分支是相互排斥的,但看起来您的 Prolog 系统并没有那么强大。如果您可以免费获得的任何 Prolog 能够在没有选择点的情况下做到这一点,我至少会感到有点惊讶。特别是如果你的实际情况更复杂,就像你说的那样。
如果您希望本文更具可读性,一些提示:
一般来说,从不在行尾使用;
,就好像它只是,
的变体一样。很容易错过它,因为一般期望行以 ,
结尾。尝试以某种真正使 ;
突出显示的方式格式化您的代码(参见下面的示例)。
一般来说,如果你想使用;
(不是_ -> _ ; _
),特别是作为子句中的单个top-level目标,考虑使用单独的子句相反:
a_iff_b(a, b).
a_iff_b(X, Y) :-
X \= a,
Y \= b.
无论如何,以下所有方法都是减少选择的可能方法:
a_iff_b_1(a, b) :-
!.
a_iff_b_1(X, Y) :-
X \= a,
Y \= b.
a_iff_b_2(X, Y) :-
( X = a, Y = b
-> true
; X \= a, Y \= b ).
a_iff_b_3(X, Y) :-
( X = a, Y = b,
!
; X \= a, Y \= b ).
a_iff_b_4(X, Y) :-
( X = a, Y = b
; X \= a, Y \= b ),
!.
a_iff_b_5(X, Y) :-
once(( X = a, Y = b
; X \= a, Y \= b )).
我想在我的 Prolog 代码中实现一个简单的 当且仅当 关系。这是我想要的一个简单示例:
?- a_iff_b(a, b).
true.
?- a_iff_b(x, x).
true.
?- a_iff_b(a, x).
false.
?- a_iff_b(x, b).
false.
你明白了——如果第一个参数是 a
而第二个参数是 b
或者如果第一个参数既不是 a
也不是第二个b
。我希望这是有道理的。从数学上讲,X = a <==> Y = b
.
这是我的尝试:
a_iff_b(X, Y) :-
X = a, Y = b;
X \= a, Y \= b.
但是这段代码引入了一个选择点:
?- a_iff_b(a, b).
true ;
false.
为什么?好像是下面的作品,我的意思是没有介绍选择点:
a_iff_b(X, Y) :- (X = a -> Y = b; Y \= b).
但是,我发现这有点可读性差,特别是因为在我的实际谓词中,等价的两侧更复杂(它们也是谓词)。
您的代码引入了一个选择点,因为它包含由 ;
运算符引入的选择。您可能会认为这是一个“逻辑或”运算符,在某种程度上它是非正式的。但在程序上它是一个“在这里引入一个选择点,并且在回溯时,也探索第二个分支”的操作符。
一个足够强大的 Prolog Compiler™ 确实能够识别出这里的两个分支是相互排斥的,但看起来您的 Prolog 系统并没有那么强大。如果您可以免费获得的任何 Prolog 能够在没有选择点的情况下做到这一点,我至少会感到有点惊讶。特别是如果你的实际情况更复杂,就像你说的那样。
如果您希望本文更具可读性,一些提示:
一般来说,从不在行尾使用
;
,就好像它只是,
的变体一样。很容易错过它,因为一般期望行以,
结尾。尝试以某种真正使;
突出显示的方式格式化您的代码(参见下面的示例)。一般来说,如果你想使用
;
(不是_ -> _ ; _
),特别是作为子句中的单个top-level目标,考虑使用单独的子句相反:a_iff_b(a, b). a_iff_b(X, Y) :- X \= a, Y \= b.
无论如何,以下所有方法都是减少选择的可能方法:
a_iff_b_1(a, b) :-
!.
a_iff_b_1(X, Y) :-
X \= a,
Y \= b.
a_iff_b_2(X, Y) :-
( X = a, Y = b
-> true
; X \= a, Y \= b ).
a_iff_b_3(X, Y) :-
( X = a, Y = b,
!
; X \= a, Y \= b ).
a_iff_b_4(X, Y) :-
( X = a, Y = b
; X \= a, Y \= b ),
!.
a_iff_b_5(X, Y) :-
once(( X = a, Y = b
; X \= a, Y \= b )).