2

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

false
  • 10,264
  • 13
  • 101
  • 209

2 Answers2

3

Why does your program fail? Evidently, your program is (for whatever reason) too specialized. So let us generalize your program such that it still fails but at least be a little bit smaller. For this purpose, let us use * to remove goals and thereby generalize the program. And also your query can be generalized by replacing the sublist [1,4,1] by a simple underscore.

:- op(950, fy, *).
* _. % the goal is just true instead

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.

?- checkCollisionDiagonal(1, [2|_/*,1,4,1*/], 1, X) ).
   false.

Because this generalized program fails, also your original program fails. So now you have a much smaller part to find the error in question (which has been given away by another answer already).

false
  • 10,264
  • 13
  • 101
  • 209
2

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.

repeat
  • 18,496
  • 4
  • 54
  • 166
TessellatingHeckler
  • 27,511
  • 4
  • 48
  • 87