Consider what I have tried:
dif_to_orto(A, B, C) :-
( dif(A, B)
; dif(A, C)
).
While this definition is fine from a declarative viewpoint it contains many redundancies. Think of:
?- dif_to_orto(A, B, C), A = 1, B = 2, C = 2.
A = 1, B = 2, C = 2
; A = 1, B = 2, C = 2. % unexpected redundant solution
And not even in this case:
?- dif_to_orto(A, B, C), A = 1, B = 2, C = 3.
A = 1, B = 2, C = 3
; A = 1, B = 2, C = 3. % unexpected redundant solution
At least, here is a case without redundancy...
?- dif_to_orto(A, B, C), A = 1, B = 2, C = 1.
A = 1, B = 2, C = 1
; false. % unexpected inefficient leftover choicepoint
...but with a resource-wasting leftover choicepoint.
Rare are the occasions where this definition is efficient:
?- dif_to_orto(A, B, C), A = 1, B = 1, C = 2.
A = 1, B = 1, C = 2.
Also that the most general query produces two answers sounds very inefficient to me:
?- dif_to_orto(A, B, C).
dif:dif(A,B)
; dif:dif(A,C).
... which produces also the following redundancy:
?- dif_to_orto(1, B, B).
dif:dif(1,B)
; dif:dif(1,B). % unexpected redundant answer
One dif/2
would be enough!
Is there a way to avoid all these redundancies and inefficiencies?
How about this one:
dif_to_orto(A, B, C) :-
dif(A-A, B-C).
The test cases:
?- dif_to_orto(A, B, C), A = 1, B = 2, C = 2.
A = 1,
B = C, C = 2.
?- dif_to_orto(A, B, C), A = 1, B = 2, C = 3.
A = 1,
B = 2,
C = 3.
?- dif_to_orto(A, B, C), A = 1, B = 2, C = 1.
A = C, C = 1,
B = 2.
?- dif_to_orto(A, B, C), A = 1, B = 1, C = 2.
A = B, B = 1,
C = 2.
?- dif_to_orto(A, B, C).
dif(f(B, A), f(A, C)).
?- dif_to_orto(1, B, B).
dif(B, 1).
Expanding on the definition of dif/2:
dif_to_orto(A, B, C):-
when((?=(A,B), ?=(A, C)), (A \== B -> true ; A \== C)).
Sample runs:
?- dif_to_orto(A, B, C), A = 1, B = 2, C = 2.
A = 1,
B = C, C = 2.
?- dif_to_orto(A, B, C), A = 1, B = 2, C = 3.
A = 1,
B = 2,
C = 3.
?- dif_to_orto(A, B, C), A = 1, B = 2, C = 1.
A = C, C = 1,
B = 2.
?- dif_to_orto(A, B, C).
when((?=(A, B), ?=(A, C)), (A\==B->true;A\==C)).
Here is one suggestion. As far as I can tell, it does not create choice points or redundant solutions:
dif_to_orto(A, B, C) :-
when(?=(A,B),(A==B->dif(A,C);true)),
when(?=(A,C),(A==C->dif(A,B);true)).
For each disjunct, wait until it is known to be true or false. Once known, check its truth and, if false, then post the other disjunct.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With