如何定义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.
我已经定义了
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.