How to define (and name) the corresponding safe term comparison predicates in ISO Prolog?

后端 未结 8 2080
萌比男神i
萌比男神i 2020-12-01 17:53

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

相关标签:
8条回答
  • 2020-12-01 18:39

    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.

    0 讨论(0)
  • 2020-12-01 18:40

    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
    

    Edit 2015-05-06

    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).
    • Shared variables of 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.
    • In the copied terms, the variables that are in X but not in Y (and vice versa) are unified with T_alpha / T_omega.
      • If this has an impact on term ordering, we cannot yet decide the ordering.
      • If it does not, we're done.

    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
    
    0 讨论(0)
提交回复
热议问题