序言中的等价关系

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 )).