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

后端 未结 8 2082
萌比男神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:17

    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:

    • Explicit traversal of recursive terms.
    • Based on prolog-coroutining facilities, in particular when/2.

      • The comparison may progress gradually:

        • "freeze" whenever instantiation is not sufficient
        • "wake up" whenever the instantiation of the most significant terms change
      • The current frontline of the comparison is represented as an explicit (LIFO) stack.

      • The current state is directly passed around the residual goals.

    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:

    • The "text volume" of residual goals appears kind of "bloated".
    • The query ?- safe_term_less_than(X+2, Y+1), X = Y. fails—just like it should!

提交回复
热议问题