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

How can I define Prolog rule to achieve bidirectional query?

提问人:Xiaoyong Guo 提问时间:2/17/2022 最后编辑:falseXiaoyong Guo 更新时间:2/19/2022 访问量:71

问:

我已经定义了

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

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

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

是否可以定义一个双向有效的规则?

序言

评论


答:

1赞 Will Ness 2/17/2022 #1

是的,您需要检查哪些变量尚未设置,并采取相应的措施。没有错误检查的骨架代码:

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.

以实现相同的目的。

0赞 Nicholas Carey 2/19/2022 #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 .
    

    如果你走这条路,如果你愿意,可以添加第四个情况,这将产生一个无限的数字序列和它们的双精度:

    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.