View source with formatted comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c) 2008-2020, University of Amsterdam,
    7                             VU University
    8                             SWI-Prolog Solutions b.v.
    9    Amsterdam All rights reserved.
   10
   11    Redistribution and use in source and binary forms, with or without
   12    modification, are permitted provided that the following conditions
   13    are met:
   14
   15    1. Redistributions of source code must retain the above copyright
   16       notice, this list of conditions and the following disclaimer.
   17
   18    2. Redistributions in binary form must reproduce the above copyright
   19       notice, this list of conditions and the following disclaimer in
   20       the documentation and/or other materials provided with the
   21       distribution.
   22
   23    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   24    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   25    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   26    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   27    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   28    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   29    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   30    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   31    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   33    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   34    POSSIBILITY OF SUCH DAMAGE.
   35*/
   36
   37:- module(terms,
   38          [ term_hash/2,                % @Term, -HashKey
   39            term_hash/4,                % @Term, +Depth, +Range, -HashKey
   40            term_size/2,                % @Term, -Size
   41            term_variables/2,           % @Term, -Variables
   42            term_variables/3,           % @Term, -Variables, +Tail
   43            variant/2,                  % @Term1, @Term2
   44            subsumes/2,                 % +Generic, @Specific
   45            subsumes_chk/2,             % +Generic, @Specific
   46            cyclic_term/1,              % @Term
   47            acyclic_term/1,             % @Term
   48            term_subsumer/3,            % +Special1, +Special2, -General
   49            term_factorized/3,          % +Term, -Skeleton, -Subsitution
   50            mapargs/3,                  % :Goal, ?Term1, ?Term2
   51            same_functor/2,             % ?Term1, ?Term2
   52            same_functor/3,             % ?Term1, ?Term2, -Arity
   53            same_functor/4              % ?Term1, ?Term2, ?Name, ?Arity
   54          ]).   55
   56:- meta_predicate
   57    mapargs(2,?,?).   58
   59:- autoload(library(rbtrees),
   60	    [ rb_empty/1,
   61	      rb_lookup/3,
   62	      rb_insert/4,
   63	      rb_new/1,
   64	      rb_visit/2,
   65	      ord_list_to_rbtree/2,
   66	      rb_update/5
   67	    ]).   68:- autoload(library(error), [instantiation_error/1]).   69
   70
   71/** <module> Term manipulation
   72
   73Compatibility library for term manipulation  predicates. Most predicates
   74in this library are provided as SWI-Prolog built-ins.
   75
   76@compat YAP, SICStus, Quintus.  Not all versions of this library define
   77        exactly the same set of predicates, but defined predicates are
   78        compatible.
   79*/
   80
   81%!  term_size(@Term, -Size) is det.
   82%
   83%   True if Size is the size  in   _cells_  occupied  by Term on the
   84%   global (term) stack. A _cell_ is 4  bytes on 32-bit machines and
   85%   8 bytes on 64-bit machines. The  calculation does take _sharing_
   86%   into account. For example:
   87%
   88%   ```
   89%   ?- A = a(1,2,3), term_size(A,S).
   90%   S = 4.
   91%   ?- A = a(1,2,3), term_size(a(A,A),S).
   92%   S = 7.
   93%   ?- term_size(a(a(1,2,3), a(1,2,3)), S).
   94%   S = 11.
   95%   ```
   96%
   97%   Note that small objects such as atoms  and small integers have a
   98%   size 0. Space is allocated for   floats, large integers, strings
   99%   and compound terms.
  100
  101term_size(Term, Size) :-
  102    '$term_size'(Term, _, Size).
  103
  104%!  variant(@Term1, @Term2) is semidet.
  105%
  106%   Same as SWI-Prolog =|Term1 =@= Term2|=.
  107
  108variant(X, Y) :-
  109    X =@= Y.
  110
  111%!  subsumes_chk(@Generic, @Specific)
  112%
  113%   True if Generic can be made equivalent to Specific without
  114%   changing Specific.
  115%
  116%   @deprecated Replace by subsumes_term/2.
  117
  118subsumes_chk(Generic, Specific) :-
  119    subsumes_term(Generic, Specific).
  120
  121%!  subsumes(+Generic, @Specific)
  122%
  123%   True  if  Generic  is  unified   to  Specific  without  changing
  124%   Specific.
  125%
  126%   @deprecated It turns out that calls to this predicate almost
  127%   always should have used subsumes_term/2.  Also the name is
  128%   misleading.  In case this is really needed, one is adviced to
  129%   follow subsumes_term/2 with an explicit unification.
  130
  131subsumes(Generic, Specific) :-
  132    subsumes_term(Generic, Specific),
  133    Generic = Specific.
  134
  135%!  term_subsumer(+Special1, +Special2, -General) is det.
  136%
  137%   General is the most specific term   that  is a generalisation of
  138%   Special1 and Special2. The  implementation   can  handle  cyclic
  139%   terms.
  140%
  141%   @compat SICStus
  142%   @author Inspired by LOGIC.PRO by Stephen Muggleton
  143
  144%       It has been rewritten by  Jan   Wielemaker  to use the YAP-based
  145%       red-black-trees as mapping rather than flat  lists and use arg/3
  146%       to map compound terms rather than univ and lists.
  147
  148term_subsumer(S1, S2, G) :-
  149    cyclic_term(S1),
  150    cyclic_term(S2),
  151    !,
  152    rb_empty(Map),
  153    lgg_safe(S1, S2, G, Map, _).
  154term_subsumer(S1, S2, G) :-
  155    rb_empty(Map),
  156    lgg(S1, S2, G, Map, _).
  157
  158lgg(S1, S2, G, Map0, Map) :-
  159    (   S1 == S2
  160    ->  G = S1,
  161        Map = Map0
  162    ;   compound(S1),
  163        compound(S2),
  164        functor(S1, Name, Arity),
  165        functor(S2, Name, Arity)
  166    ->  functor(G, Name, Arity),
  167        lgg(0, Arity, S1, S2, G, Map0, Map)
  168    ;   rb_lookup(S1+S2, G0, Map0)
  169    ->  G = G0,
  170        Map = Map0
  171    ;   rb_insert(Map0, S1+S2, G, Map)
  172    ).
  173
  174lgg(Arity, Arity, _, _, _, Map, Map) :- !.
  175lgg(I0, Arity, S1, S2, G, Map0, Map) :-
  176    I is I0 + 1,
  177    arg(I, S1, Sa1),
  178    arg(I, S2, Sa2),
  179    arg(I, G, Ga),
  180    lgg(Sa1, Sa2, Ga, Map0, Map1),
  181    lgg(I, Arity, S1, S2, G, Map1, Map).
  182
  183
  184%!  lgg_safe(+S1, +S2, -G, +Map0, -Map) is det.
  185%
  186%   Cycle-safe version of the  above.  The   difference  is  that we
  187%   insert compounds into the mapping table   and  check the mapping
  188%   table before going into a compound.
  189
  190lgg_safe(S1, S2, G, Map0, Map) :-
  191    (   S1 == S2
  192    ->  G = S1,
  193        Map = Map0
  194    ;   rb_lookup(S1+S2, G0, Map0)
  195    ->  G = G0,
  196        Map = Map0
  197    ;   compound(S1),
  198        compound(S2),
  199        functor(S1, Name, Arity),
  200        functor(S2, Name, Arity)
  201    ->  functor(G, Name, Arity),
  202        rb_insert(Map0, S1+S2, G, Map1),
  203        lgg_safe(0, Arity, S1, S2, G, Map1, Map)
  204    ;   rb_insert(Map0, S1+S2, G, Map)
  205    ).
  206
  207lgg_safe(Arity, Arity, _, _, _, Map, Map) :- !.
  208lgg_safe(I0, Arity, S1, S2, G, Map0, Map) :-
  209    I is I0 + 1,
  210    arg(I, S1, Sa1),
  211    arg(I, S2, Sa2),
  212    arg(I, G, Ga),
  213    lgg_safe(Sa1, Sa2, Ga, Map0, Map1),
  214    lgg_safe(I, Arity, S1, S2, G, Map1, Map).
  215
  216
  217%!  term_factorized(+Term, -Skeleton, -Substiution)
  218%
  219%   Is true when Skeleton is  Term   where  all subterms that appear
  220%   multiple times are replaced by a  variable and Substitution is a
  221%   list of Var=Value that provides the subterm at the location Var.
  222%   I.e., After unifying all substitutions  in Substiutions, Term ==
  223%   Skeleton. Term may be cyclic. For example:
  224%
  225%     ==
  226%     ?- X = a(X), term_factorized(b(X,X), Y, S).
  227%     Y = b(_G255, _G255),
  228%     S = [_G255=a(_G255)].
  229%     ==
  230
  231term_factorized(Term, Skeleton, Substitutions) :-
  232    rb_new(Map0),
  233    add_map(Term, Map0, Map),
  234    rb_visit(Map, Counts),
  235    common_terms(Counts, Common),
  236    (   Common == []
  237    ->  Skeleton = Term,
  238        Substitutions = []
  239    ;   ord_list_to_rbtree(Common, SubstAssoc),
  240        insert_vars(Term, Skeleton, SubstAssoc),
  241        mk_subst(Common, Substitutions, SubstAssoc)
  242    ).
  243
  244add_map(Term, Map0, Map) :-
  245    (   primitive(Term)
  246    ->  Map = Map0
  247    ;   rb_update(Map0, Term, Old, New, Map)
  248    ->  New is Old+1
  249    ;   rb_insert(Map0, Term, 1, Map1),
  250        assoc_arg_map(1, Term, Map1, Map)
  251    ).
  252
  253assoc_arg_map(I, Term, Map0, Map) :-
  254    arg(I, Term, Arg),
  255    !,
  256    add_map(Arg, Map0, Map1),
  257    I2 is I + 1,
  258    assoc_arg_map(I2, Term, Map1, Map).
  259assoc_arg_map(_, _, Map, Map).
  260
  261primitive(Term) :-
  262    var(Term),
  263    !.
  264primitive(Term) :-
  265    atomic(Term),
  266    !.
  267primitive('$VAR'(_)).
  268
  269common_terms([], []).
  270common_terms([H-Count|T], List) :-
  271    !,
  272    (   Count == 1
  273    ->  common_terms(T, List)
  274    ;   List = [H-_NewVar|Tail],
  275        common_terms(T, Tail)
  276    ).
  277
  278insert_vars(T0, T, _) :-
  279    primitive(T0),
  280    !,
  281    T = T0.
  282insert_vars(T0, T, Subst) :-
  283    rb_lookup(T0, S, Subst),
  284    !,
  285    T = S.
  286insert_vars(T0, T, Subst) :-
  287    functor(T0, Name, Arity),
  288    functor(T,  Name, Arity),
  289    insert_arg_vars(1, T0, T, Subst).
  290
  291insert_arg_vars(I, T0, T, Subst) :-
  292    arg(I, T0, A0),
  293    !,
  294    arg(I, T,  A),
  295    insert_vars(A0, A, Subst),
  296    I2 is I + 1,
  297    insert_arg_vars(I2, T0, T, Subst).
  298insert_arg_vars(_, _, _, _).
  299
  300mk_subst([], [], _).
  301mk_subst([Val0-Var|T0], [Var=Val|T], Subst) :-
  302    functor(Val0, Name, Arity),
  303    functor(Val,  Name, Arity),
  304    insert_arg_vars(1, Val0, Val, Subst),
  305    mk_subst(T0, T, Subst).
  306
  307
  308%!  mapargs(:Goal, ?Term1, ?Term2)
  309%
  310%   Term1 and Term2 have the  same   functor  (name/arity)  and for each
  311%   matching pair of arguments call(Goal, A1, A2) is true.
  312
  313mapargs(Goal, Term1, Term2) :-
  314    same_functor(Term1, Term2, Arity),
  315    mapargs_(1, Arity, Goal, Term1, Term2).
  316
  317mapargs_(I, Arity, Goal, Term1, Term2) :-
  318    I =< Arity,
  319    !,
  320    arg(I, Term1, A1),
  321    arg(I, Term2, A2),
  322    call(Goal, A1, A2),
  323    I2 is I+1,
  324    mapargs_(I2, Arity, Goal, Term1, Term2).
  325mapargs_(_, _, _, _, _).
  326
  327
  328%!  same_functor(?Term1, ?Term2) is semidet.
  329%!  same_functor(?Term1, ?Term2, -Arity) is semidet.
  330%!  same_functor(?Term1, ?Term2, ?Name, ?Arity) is semidet.
  331%
  332%   True when Term1 and Term2 are  compound   terms  that  have the same
  333%   functor   (Name/Arity).   The   arguments   must   be   sufficiently
  334%   instantiated, which means either Term1  or   Term2  must be bound or
  335%   both Name and Arity must be bound.
  336%
  337%   @compat SICStus
  338
  339same_functor(Term1, Term2) :-
  340    same_functor(Term1, Term2, _Name, _Arity).
  341
  342same_functor(Term1, Term2, Arity) :-
  343    same_functor(Term1, Term2, _Name, Arity).
  344
  345same_functor(Term1, Term2, Name, Arity) :-
  346    (   nonvar(Term1)
  347    ->  compound_name_arity(Term1, Name, Arity),
  348        compound_name_arity(Term2, Name, Arity)
  349    ;   nonvar(Term2)
  350    ->  compound_name_arity(Term2, Name, Arity),
  351        compound_name_arity(Term1, Name, Arity)
  352    ;   nonvar(Name),
  353        nonvar(Arity)
  354    ->  compound_name_arity(Term1, Name, Arity),
  355        compound_name_arity(Term2, Name, Arity)
  356    ;   instantiation_error(Term1)
  357    )