如何定义Prolog规则来实现双向查询?

How can I define Prolog rule to achieve bidirectional query?

我已经定义了

double(X,Y) :- Y is X*2.

当我查询 double(3,Y) 时,我得到 Y=6

但是当我查询double(X,6),时,我无法得到X=3

是否可以定义一个双向适用的规则?

是的,您需要检查哪些变量尚未设置,并据此采取行动。骨架代码,没有错误检查:

double(X,Y) :-  % Y = 2*X
  (  var(X) ->
      (  var(Y) -> freeze(X, double(X,Y)),
                   freeze(Y, double(X,Y))
      ;  X is Y/2
      )
  ;  Y is 2*X
  ).

这给了我们,在 SWI Prolog 中,

33 ?- double(3,6).
true.

34 ?- double(3,Y).
Y = 6.

35 ?- double(X,6).
X = 3.

36 ?- double(X,Y).
freeze(X, double(X, Y)),
freeze(Y, double(X, Y)).

37 ?- double(X,Y),Y=6.
X = 3,
Y = 6.

38 ?- double(X,Y),X=3.
X = 3,
Y = 6.

39 ?- double(X,Y),X=3,Y=41.
false.

或者,您可以这样做

41 ?- use_module( library(clpfd)).
true.

42 ?- [user].
double(X,Y):- Y #= X * 2.

实现相同。

我可能会这样做:

double(X,Y) :- nonvar(X),            Y is X * 2 .
double(X,Y) :-            nonvar(Y), X is Y / 2 .

虽然当两个参数都被实例化时,这确实让您有可能获得 2 个解决方案(double(3,1.5). 将成功两次)。

您可以通过多种方式解决该问题:

  • 使用剪切消除无关的选择点。

    double(X,Y) :- nonvar(X),            Y is X * 2 , ! .
    double(X,Y) :-            nonvar(Y), X is Y / 2     .
    
  • 添加额外的类型检查。

    double(X,Y) :- nonvar(X),    var(Y), Y is X * 2 .
    double(X,Y) :-            nonvar(Y), X is Y / 2 .
    
  • 或更多:

    double(X,Y) :- nonvar(X), nonvar(Y), X =:= Y .
    double(X,Y) :- nonvar(X),    var(Y), Y is X * 2 .
    double(X,Y) :-    var(X), nonvar(Y), X is Y / 2 .
    

    如果你走那条路,可以添加第 4 种情况,如果你愿意,这将产生无限的数字序列及其双精度数:

    double(X,Y) :- nonvar(X), nonvar(Y), X =:= Y .
    double(X,Y) :- nonvar(X),    var(Y), Y is X * 2 .
    double(X,Y) :-    var(X), nonvar(Y), X is Y / 2 .
    double(X,Y) :-    var(X),    var(Y), between(0,infinity), Y is X * 2.