Search code examples
prologprolog-dif

What is never equal to itself?


Is there value in Prolog that is not equal to itself? I write answer to some question about min of tree and this answer also says that if tree is empty min is null. Sounds good idea first but now when I think it sounds like bad idea.

It is kinda OK if null <> null, no problem. But in Prolog I see null is just atom so....

?- null = null.
true.

?- null == null.
true.

?- dif(null, null).
false.

How can I make some term in Prolog that always say:

?- dif(Something, Something).
true.

But if it is any other thing and not this term that is the null thing still say false.?

Or if this is not how I should think in Prolog then how should I think about not true. and also not false. but "neither true nor false because something is missing"?


Solution

  • 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