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 implement
In this answer we present the predicate safe_term_less_than/2
, a monotonic analogue to the iso-prolog built-in predicate (@<)/2 (§8.4.1, "term less than"). Its main properties are:
Based on prolog-coroutining facilities, in particular when/2.
The comparison may progress gradually:
The current frontline of the comparison is represented as an explicit (LIFO) stack.
The following code has been developed and tested on sicstus-prolog version 4.3.2:
safe_term_less_than(L, R) :- % exported predicate
i_less_than_([L-R]).
Above definition of safe_term_less_than/2
is based on the following auxiliary predicates:
i_less_than_([L-R|LRs]) :- Cond = (?=(L,R) ; nonvar(L),nonvar(R)), when(Cond, i_lt_step_(L,R,LRs)). i_lt_step_(L, R, LRs) :- ( L == R -> i_less_than_(LRs) ; term_itype(L, L_type), term_itype(R, R_type), compare(Ord, L_type, R_type), ord_lt_step_(Ord, L, R, LRs) ). term_itype(V, T) :- ( var(V) -> throw(error(instantiation_error,_)) ; float(V) -> T = t1_float(V) ; integer(V) -> T = t2_integer(V) ; callable(V) -> T = t3_callable(A,F), functor(V, F, A) ; throw(error(system_error,_)) ). ord_lt_step_(<, _, _, _). ord_lt_step_(=, L, R, LRs) :- ( compound(L) -> L =.. [_|Ls], R =.. [_|Rs], phrase(args_args_paired(Ls,Rs), LRs0, LRs), i_less_than_(LRs0) ; i_less_than_(LRs) ). args_args_paired([], []) --> []. args_args_paired([L|Ls], [R|Rs]) --> [L-R], args_args_paired(Ls, Rs).
Sample queries:
| ?- safe_term_less_than(X, 3). prolog:trig_nondif(X,3,_A,_B), prolog:trig_or([_B,X],_A,_A), prolog:when(_A,(?=(X,3);nonvar(X),nonvar(3)),user:i_lt_step_(X,3,[])) ? yes | ?- safe_term_less_than(X, 3), X = 4. no | ?- safe_term_less_than(X, 3), X = 2. X = 2 ? ; no | ?- safe_term_less_than(X, a). prolog:trig_nondif(X,a,_A,_B), prolog:trig_or([_B,X],_A,_A), prolog:when(_A,(?=(X,a);nonvar(X),nonvar(a)),user:i_lt_step_(X,a,[])) ? ; no | ?- safe_term_less_than(X, a), X = a. no | ?- safe_term_less_than(X+2, Y+1), X = Y. no
In comparison to previous answers, we observe:
?- safe_term_less_than(X+2, Y+1), X = Y.
fails—just like it should!