问题描述
考虑我已经尝试过的:
dif_to_orto(A,B,C) :-
( dif(A,B)
; dif(A,C)
).
虽然从声明性的角度来看这个定义很好,但它包含许多冗余。想想:
?- dif_to_orto(A,C),A = 1,B = 2,C = 2.
A = 1,C = 2
; A = 1,C = 2. % unexpected redundant solution
即使在这种情况下也不行:
?- dif_to_orto(A,C = 3.
A = 1,C = 3
; A = 1,C = 3. % unexpected redundant solution
至少,这是一个没有冗余的案例......
?- dif_to_orto(A,C = 1.
A = 1,C = 1
; false. % unexpected inefficient leftover choicepoint
...但是有一个浪费资源的剩余选择点。
很少有这种定义有效的情况:
?- dif_to_orto(A,B = 1,C = 2.
此外,最一般的查询产生两个答案对我来说听起来效率很低:
?- dif_to_orto(A,C).
dif:dif(A,B)
; dif:dif(A,C).
... 这也会产生以下冗余:
?- dif_to_orto(1,B).
dif:dif(1,B)
; dif:dif(1,B). % unexpected redundant answer
一个 dif/2
就足够了!
有没有办法避免所有这些冗余和低效?
解决方法
这个怎么样:
dif_to_orto(A,B,C) :-
dif(A-A,B-C).
测试用例:
?- dif_to_orto(A,C),A = 1,B = 2,C = 2.
A = 1,B = C,C = 2.
?- dif_to_orto(A,C = 3.
A = 1,C = 3.
?- dif_to_orto(A,C = 1.
A = C,C = 1,B = 2.
?- dif_to_orto(A,B = 1,C = 2.
A = B,C).
dif(f(B,A),f(A,C)).
?- dif_to_orto(1,B).
dif(B,1).
,
此解决方案首先等待 3 个变量中的 2 个具有可比性,然后如果无法确定约束是否应该成功,则添加一个新约束:
dif_to_orto(A,C) :-
when((?=(A,B) ; ?=(A,C) ; ?=(B,C)),( ?=(A,B) ->
( A\==B -> true ; dif(A,C) )
;
(
?=(A,C) ->
( A\==C -> true ; dif(A,B) )
;
( B\==C -> true ; dif(A,B) )
)
)).
样品运行:
?- dif_to_orto(A,C).
when((?=(A,C);?=(B,C);?=(A,B)),(?=(A,B)->(A\==B->true;dif(A,C));?=(A,C)->(A\==C->true;dif(A,B));B\==C->true;dif(A,B))).
?- dif_to_orto(1,2,Z).
true.
?- dif_to_orto(1,1).
撤销支票:
dif_to_orto(A,(
A==B -> dif(A,C)
;
((A==C ; B==C) -> dif(A,B) ; true)
)).
,
这是一个建议。据我所知,它不会产生选择点或多余的解决方案:
dif_to_orto(A,C) :-
when(?=(A,B),(A==B->dif(A,C);true)),when(?=(A,(A==C->dif(A,B);true)).
对于每个析取,等待直到知道它是真还是假。一旦知道,检查它的真实性,如果是错误的,然后发布另一个分离。
,扩展dif/2的定义:
dif_to_orto(A,C):-
when((?=(A,?=(A,(A \== B -> true ; A \== C)).
样品运行:
?- dif_to_orto(A,(A\==B->true;A\==C)).