If I want to make sure that two variables do not instantiate to the same term, what is the preferred way to do it?
Let’s say I need to find directed edges in a graph, and a node cannot have an edge to itself:
node(a, x, y). node(b, z, x). node(c, y, y).
(the edges here are a -> c, b -> a, but not c -> c)
The following works:
edge(A, B) :- node(A, _, X), node(B, X, _), A \== B.
This works too [swi-prolog]:
edge(A, B) :- dif(A, B), node(A, _, X), node(B, X, _).
This does not work, apparently (because neither A nor B are instantiated yet?):
edge(A, B) :- A \== B, node(A, _, X), node(B, X, _).
I guess my problem with the first solution is that, with a more complex node predicate, a lot of unnecessary unifications might take place before edge fails. The dif on the other hand is in a library, which suggests that it is not meant to be used in such a simple case (although it has the exact function that I seem to be looking for).
For elegance and didactic reasons alone,
dif/2is clearly preferable here and also in the vast majority of other cases, since as you already note “a lot of unnecessary unifications might take place” otherwise, and also becausedif/2is a pure and nicely declarative predicate that can be used in all directions and at any place in the clause body without changing the meaning of the program, in contrast to(\==)/2.dif/2is also an autoloaded predicate in SWI-Prolog, meaning that you need not import any library explicitly to use it, anddif/2is available like any built-in predicate.If you use
dif/2you can reason much more easily about your code. For example, in your case, you start with:and then, as you know that
dif/2is a completely pure predicate, you know that you can also write this as:Further, since you know that
dif/2always terminates, you know that this change can at most improve the termination properties of your program.Like all constraints,
dif/2is meant to be used. I highly recommend it instead of impure predicates that are not commutative.In case you are worried about performance, here is a small comparison, just comparing
dif/2against the non-declarative(\==)/2in a use case where the two predicates can be used interchangeably:So, there are sometimes performance benefits when using
(\==)/2. However, there are also much more severe drawbacks when using such a low-level predicate: It is harder to understand, more error-prone, and not declarative.I therefore recommend to simply use
dif/2to express that two terms are different.