Search code examples
prologprolog-dif

Prolog bind variable to opposite of another boolean variable


I want to create a clause that will hold if its two boolean parameters are equal and the third parameter is 1 or its two boolean parameters are not equal and the third parameter is 0. My first attempt:

equal_bools(X, Y, N) :-
    X = Y,
    N=1.
equal_bools(X, Y, N) :-
    \+ X = Y,
    N=0.

This seems to work:

?- equal_bools(true, true, 0).
false.

?- equal_bools(true, true, 1).
true.

?- equal_bools(true, false, 0).
true.

?- equal_bools(true, false, 1).
false.

The problem is, I really need Y to be bound to the correct value. For example, equal_bools(false, Y, 0). should give back Y = true .. Instead:

?- equal_bools(false, Y, 0).
false.

It seems \+ X = Y checks for equality, but doesn't bind X or Y to any values. How do I fix this? This is for learning purposes, so I'd like to understand exactly how to do this rather than get a built-in clause that does all this or another library.


Solution

  • Nicely deterministic (i.e. no unwanted choicepoints), using (as usual) first-argument indexing, and unification:

    bool_opp(true, false).
    bool_opp(false, true).
    
    % Unifies X with Y
    bools_int(1, X, X) :-
        bool_opp(X, _).
    bools_int(0, X, Y) :-
        bool_opp(X, Y).
    

    Results in swi-prolog:

    ?- bools_int(I, X, Y).
    I = 1,
    X = Y, Y = true ;
    I = 1,
    X = Y, Y = false ;
    I = 0,
    X = true,
    Y = false ;
    I = 0,
    X = false,
    Y = true.
    
    ?- bools_int(1, X, Y).
    X = Y, Y = true ;
    X = Y, Y = false.
    
    ?- bools_int(0, X, Y).
    X = true,
    Y = false ;
    X = false,
    Y = true.
    
    ?- bools_int(0, X, true).
    X = false.
    
    ?- bools_int(1, X, true).
    X = true.
    
    ?- bools_int(1, X, false).
    X = false.
    
    ?- bools_int(0, X, false).
    X = true.
    
    ?- bools_int(I, X, false).
    I = 1,
    X = false ;
    I = 0,
    X = true.