Search code examples
prolog

Prolog statement never unifies


I have 3 recursive rules but one of them never unifies with my query.

checkCollisionDiagonal(QueenTarget,[],Qdist,0).
checkCollisionDiagonal(QueenTarget, [Q|QueenList], Qdist, X):-
    abs(QueenTarget - Q) =\= Qdist,
    NextQdist is Qdist + 1,
    checkCollisionDiagonal(QueenTarget, QueenList, NextQdist, X).
checkCollisionDiagonal(QueenTarget, [Q|QueenList], Qdist, X):-
    abs(QueenTarget - Q) = Qdist, 
    NextQdist is Qdist + 1,
    checkCollisionDiagonal(QueenTarget, QueenList, NextQdist, X1),
    X is X1+1.

The statement where the absolute value is different from Qdist works fine, if it doesn't unify my program should check the next statement (the one with absolute value equal to Qdist), but using trace I noticed that the second statement (abs = Qdist) is never evaluated. Why does it happens?

My query is checkCollisionDiagonal(1, [2,1,4,1], 1, X). and the expected result should be 2 but it always returns false


Solution

  • It does unify, unification is not what you want:

    ?- abs(5 - 2) = Qdist.
    Qdist = abs(5-2)
    

    They're not functions, abs() doesn't do any calculation. It's clearer if you change the words:

    ?- szz(5 $ / * foo) = Qdist.
    Qdist = szz(5$(/)*foo)
    

    Variable Qdist unifies with that term.

    You need =:=, =\=, or is which all know how to evaluate abs(5 - 2):

    • Qdist is abs(5 - 2) evaluates the right side as an arithmetic expression (abs(5 - 2)) and unifies the result with Qdist.

    • Qdist =:= abs(5 - 2) evaluates both sides as arithmetic expressions, compares the results, and succeeds if they are equal.

    • Qdist =\= abs(5 - 2) is the negation of =:=/2: it evaluates both sides as arithmetic expressions, compares the results, and succeeds if they are not equal.

    See the documentation for arithmetic predicates.