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
This answer follows up on my previous one which presented safe_term_less_than/2.
What's next? A safe variant of compare/3—unimaginatively called scompare/3:
scompare(Ord, L, R) :-
i_scompare_ord([L-R], Ord).
i_scompare_ord([], =).
i_scompare_ord([L-R|Ps], X) :-
when((?=(L,R);nonvar(L),nonvar(R)), i_one_step_scompare_ord(L,R,Ps,X)).
i_one_step_scompare_ord(L, R, LRs, Ord) :-
( L == R
-> scompare_ord(LRs, Ord)
; term_itype(L, L_type),
term_itype(R, R_type),
compare(Rel, L_type, R_type),
( Rel \== (=)
-> Ord = Rel
; compound(L)
-> L =.. [_|Ls],
R =.. [_|Rs],
phrase(args_args_paired(Ls,Rs), LRs0, LRs),
i_scompare_ord(LRs0, Ord)
; i_scompare_ord(LRs , Ord)
)
).
The predicates term_itype/2 and args_args_paired//2 are the same as defined previously.
What the heck! I'll give it a shot, too!
lt(X,Y) :-
X \== Y,
( X \= Y
-> term_variables(X,Xvars),
term_variables(Y,Yvars),
list_vars_excluded(Xvars,Yvars,XonlyVars),
list_vars_excluded(Yvars,Xvars,YonlyVars),
_ = s(T_alpha),
functor(T_omega,zzzzzzzz,255), % HACK!
copy_term(t(X,Y,XonlyVars,YonlyVars),t(X1,Y1,X1onlyVars,Y1onlyVars)),
copy_term(t(X,Y,XonlyVars,YonlyVars),t(X2,Y2,X2onlyVars,Y2onlyVars)),
maplist(=(T_alpha),X1onlyVars), maplist(=(T_omega),Y1onlyVars),
maplist(=(T_omega),X2onlyVars), maplist(=(T_alpha),Y2onlyVars),
% do T_alpha and T_omega have an impact on the order?
( compare(Cmp,X1,Y1),
compare(Cmp,X2,Y2)
-> Cmp = (<) % no: demand that X @< Y holds
; throw(error(instantiation_error,lt/2))
)
; throw(error(instantiation_error,lt/2))
).
Some more auxiliary stuff:
listHasMember_identicalTo([X|Xs],Y) :-
( X == Y
-> true
; listHasMember_identicalTo(Xs,Y)
).
list_vars_excluded([],_,[]).
list_vars_excluded([X|Xs],Vs,Zs) :-
( listHasMember_identicalTo(Vs,X)
-> Zs = Zs0
; Zs = [X|Zs0]
),
list_vars_excluded(Xs,Vs,Zs0).
Let's have some tests (with GNU Prolog 1.4.4):
?- lt(a(X,Y,c(c),Z1), a(X,Y,b(b,b),Z2)). yes ?- lt(a(X,Y,b(b,b),Z1), a(X,Y,c(c),Z2)). no ?- lt(a(X,Y1,c(c),Z1), a(X,Y2,b(b,b),Z2)). uncaught exception: error(instantiation_error,lt/2) ?- lt(a(X,Y1,b(b,b),Z1), a(X,Y2,c(c),Z2)). uncaught exception: error(instantiation_error,lt/2) ?- lt(b(b), a(a,a)). yes ?- lt(a(X), a(Y)). uncaught exception: error(instantiation_error,lt/2) ?- lt(X, 3). uncaught exception: error(instantiation_error,lt/2) ?- lt(X+a, X+b). yes ?- lt(X+a, Y+b). uncaught exception: error(instantiation_error,lt/2) ?- lt(a(X), b(Y)). yes ?- lt(a(X), a(Y)). uncaught exception: error(instantiation_error,lt/2) ?- lt(a(X), a(X)). no
Changed the implementation of lt/2 to use T_alpha and T_omega, not two fresh variables.
lt(X,Y) makes two copies of X (X1 and X2) and two copies of Y (Y1 and Y2).X and Y are also shared by X1 and Y1, and by X2 and Y2.T_alpha comes before all other terms (in X1, X2, Y1, Y2) w.r.t. the standard order.T_omega comes after all other terms in the standard order.X but not in Y (and vice versa) are unified with T_alpha / T_omega.
Now, the counterexample given by @false works:
?- lt(X+1,1+2).
uncaught exception: error(instantiation_error,lt/2)
?- X=2, lt(X+1,1+2).
no