Just for fun, not really the answer you're looking for, taking the question title quite literally:
?- _ == _ .
false.
But dif/2
is not fouled (hint: each occurrence of the anonymous variable represents a different variable):
?- dif(_, _).
true.
Now, seriously. Starting with your tree minimum predicate example, there's a trivial alternative: the predicate can simply fail when the tree is empty. A better alternative may be to use optional or expected term libraries. The concepts behind these libraries are found in several programming languages, where they provide a better alternative to null. You have both libraries in Logtalk, which you can use with most Prolog systems. See:
and
You use one library or the other depending on your interpretation of "missing" meaning something that is optional (absence of a value is fine) or expected (absence of a value is an error). For example, assume that in your particular application it makes sense to use 0
as the minimum value of an empty tree when doing a specific computation (e.g. the sum of the minimums of a set of trees). If the tree minimum predicate returns an optional term reference, Ref
, instead of an integer, you could do e.g.
...,
optional(Ref)::or_else(Minimum, 0),
Sum1 is Sum0 + Minimum,
...
This is a cleaner solution compared with using an if-then-else construct:
...,
( tree_minimum(Tree, Minimum) ->
Sum1 is Sum0 + Minimum
; Sum1 is Sum0
),
...
It also allows you to use different defaults for different computations. For example:
...,
optional(Ref)::or_else(Minimum, 1),
Product1 is Product0 * Minimum,
...
More important, it doesn't mask that you're processing an empty tree in the same way that a default value would do. For example, the following code will only write the minimum values of non-empty trees:
print_tree_minimums(Refs) :-
meta::map(print_tree_minimum, Refs).
print_tree_minimum(Ref) :-
optional(Ref)::if_present(write).
or, using a lambda expression:
print_tree_minimums(Refs) :-
meta::map([Ref]>>(optional(Ref)::if_present(write)), Refs).
This answer is getting long and I don't want to transform it into a general discussion of the pros and cons of optionals and expecteds. But descriptions on both concepts and libraries is easy to find. E.g.
https://en.wikipedia.org/wiki/Option_type
https://youtu.be/NhcHwkUPX7w
=
operator is not simply a way of asking if two things are equal, it is the heart and soul of unification itself which is one of the two major differences between Prolog and all other languages. It would be quite a strange and warty mess if that operator sometimes did not unify simply because some imperative programmer came along wanting to repeat the billion dollar mistake. Again, you could make your own equality predicate, but as you suspect, null is just a bad idea that has no place in declarative programming. – Daniel Lyonsnull
. As your code in that answer shows, it does become a little cumbersome dealing with thenull
case. It's easier to just define the predicate such that it succeeds if there is a minimum, but fails otherwise. Which is better? It depends upon the use case, which often isn't given in such questions. – lurkernull
itself, as you say, is just an atom. It has no truth value.null \= null
must be false sincenull
is an atom and, in Prolog, if two atoms are identical, they are necessarily (trivially) unifiable. – lurker