Standard term order (ISO/IEC 13211-1 7.2 Term order) is defined over all terms — including variables. While there are good uses for this — think of the implementation of setof/3
, this makes many otherwise clean and logical uses of the built-ins in 8.4 Term comparison a declarative nightmare with imps (short form for imperative constructs) all around. 8.4 Term comparison features:
8.4 Term comparison
8.4.1 (@=<)/2, (==)/2, (==)/2, (@<)/2, (@>)/2, (@>=)/2.
8.4.2 compare/3.
8.4.3 sort/2.
8.4.4 keysort/2.
To give an example, consider:
?- X @< a.
true.
This succeeds, because
7.2 Term order
An ordering term_precedes (3.181) defines whether or
not a termX
term-precedes a termY
.If
X
andY
are identical terms thenX
term_precedesY
andY
term_precedesX
are both false.If
X
andY
have different types:X
term_precedesY
iff the
type ofX
precedes the type ofY
in the following order:
variable
precedesfloating point
precedesinteger
precedesatom
precedescompound
.NOTE — Built-in predicates which test the ordering of terms
are defined in 8.4.
...
And thus all variables are smaller than a
. But once X
is instantiated:
?- X @< a, X = a.
X = a.
the result becomes invalid.
So that is the problem. To overcome this, one might either use constraints, or stick to core behavior only and therefore produce an instantiation_error
.
7.12.2 Error classification
Errors are classified according to the form of
Error_term
:a) There shall be an Instantiation Error when an
argument or one of its components is a variable, and an
instantiated argument or component is required. It has
the forminstantiation_error
.
In this manner we know for sure that a result is well defined as long as no instantiation error occurs.
For (\==)/2
, there is already either dif/2
which uses constraints or dif_si/2
(formerly iso_dif/2
) which produces a clean instantiation error.
dif_si(X, Y) :-
X \== Y,
( X \= Y -> true
; throw(error(instantiation_error,dif_si/2))
).
So what my question is about: How to define (and name) the corresponding safe term comparison predicates in ISO Prolog? Ideally, without any explicit term traversal. Maybe to clarify: Above dif_si/2
does not use any explicit term traversal. Both (\==)/2
and (\=)/2
traverse the term internally, but the overheads for this are extremely low compared to explicit traversal with (=..)/2
or functor/3, arg/3
.
freeze/2
? – Paranymphfreeze/2
alone would not work properly, you would rather needwhen/2
with?=
. Example:lt(X+2,Y+1), X = Y
should fail already. – Ultan