First of all, dif/2
and (\==)/2
mean the same when both arguments are ground, that is variable free. So if you can ensure that the arguments will be ground — or rather sufficiently instantiated such that further instantiations will not affect the outcome of (\==)/2
— then it does not make a difference.
In your example, we would need to know for sure that answers for node/3
contain always a ground first argument. In that case, the (\==)/2
program is fine. In rare cases it might be less efficient than the dif/2
version. Think of the goal edge(X, X)
.
In many situations, the (\==)/2
or even (\=)/2
is significantly more efficient. On the other hand, how important is efficiency when compared to correctness?
Another way of seeing this, is to consider (\==)/2
and (\=)/2
as approximations from two sides: Only if both agree, do we have a safe final outcome.
Historically, dif/2
is one of the oldest built-in predicates. It was present in the very first Prolog system which is sometimes called Prolog 0 to distinguish it from the next version which is often perceived to be the first Prolog — the Marseille Prolog — Prolog 1. Prolog 1 did no longer have dif/2
and it is in this shape that Prolog came to Edinburgh. Also,dif/2
is not part of the ISO standard (currently) since it requires some coroutining-like mechanism. And many (rather older) Prolog systems do not have such a mechanism. However, even in ISO Prolog one could do better:
dif_si(X, Y) :-
X == Y,
!,
fail.
dif_si(X, Y) :-
X \= Y,
!.
dif_si(X, Y) :-
throw(error(instantiation_error,iso_dif/2)).
(Here is another, probably more efficient implementation)
Note how the problematic cases are covered by an error that stops the entire computation.
Current Prolog systems that support dif/2
right out of the box are B, SICStus, SWI, YAP. It is in a library of IF, Ciao, XSB, Scryer.
See also this answer.
To support my claim about the overheads, here is a test in various Prologs on the same machine. In SWI, there is an overhead of a factor of 10, in B, there is no overhead. As has been noted by @nfz, numbers are slightly different when compiling things. So your mileage may vary.
SWI 6.3.4-55
?- 1000=I,time(( dif(X,Y), between(1,I,X), between(1,I,Y), false )).
% 22,999,020 inferences, 5.162 CPU in 5.192 seconds (99% CPU, 4455477 Lips)
false.
?- 1000=I,time(( between(1,I,X), between(1,I,Y), X \== Y, false )).
% 2,000,001 inferences, 0.511 CPU in 0.521 seconds (98% CPU, 3912566 Lips)
false.
B 7.8
| ?- 1000=I,time(( dif(X,Y), between(1,I,X), between(1,I,Y), false )).
CPU time 0.364 seconds.
no
| ?- 1000=I,time(( between(1,I,X), between(1,I,Y), X \== Y, false )).
CPU time 0.356 seconds.
no
YAP
?- 1000=I,time(( dif(X,Y), between(1,I,X), between(1,I,Y), false )).
% 2.528 CPU in 2.566 seconds ( 98% CPU)
no
?- 1000=I,time(( between(1,I,X), between(1,I,Y), X \== Y, false )).
% 0.929 CPU in 0.963 seconds ( 96% CPU)
no
node/3
in my question is doing and I am having trouble. Who knows what I was smoking when I wrote this question. It seems that I was solving some problem in which I know something about the graph but not its actual topology yet: this is somehow encoded innode/3
. I could not track down the motivation for this question. – Ratoon