'How can I define Prolog rule to achieve bidirectional query?

I have defined

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

and when I query double(3,Y), I get Y=6.

But when I query double(X,6), I cannot get X=3.

Is it possible to define a rule that works in both directions?



Solution 1:[1]

I would probably do something like this:

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

Though that does leave you with the possibility of getting 2 solutions when both arguments are instantiated (double(3,1.5). will succeed twice).

You could fix that in a number of ways:

  • Using a cut to eliminate the extraneous choice point.

    double(X,Y) :- nonvar(X),            Y is X * 2 , ! .
    double(X,Y) :-            nonvar(Y), X is Y / 2     .
    
  • Adding an additional type check.

    double(X,Y) :- nonvar(X),    var(Y), Y is X * 2 .
    double(X,Y) :-            nonvar(Y), X is Y / 2 .
    
  • Or more:

    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 .
    

    If you went that route, one could add a 4th case, if you wanted, that would produce an infinite sequence of numbers and their doubles:

    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. 
    
    

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nicholas Carey