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            mapsubterms/3,              % :Goal, ?Term1, ?Term2
   52            same_functor/2,             % ?Term1, ?Term2
   53            same_functor/3,             % ?Term1, ?Term2, -Arity
   54            same_functor/4              % ?Term1, ?Term2, ?Name, ?Arity
   55          ]).   56
   57:- meta_predicate
   58    mapargs(2,?,?),
   59    mapsubterms(2,?,?).   60
   61:- autoload(library(rbtrees),
   62	    [ rb_empty/1,
   63	      rb_lookup/3,
   64	      rb_insert/4,
   65	      rb_new/1,
   66	      rb_visit/2,
   67	      ord_list_to_rbtree/2,
   68	      rb_update/5
   69	    ]).   70:- autoload(library(error), [instantiation_error/1]).   71
   72
   73/** <module> Term manipulation
   74
   75Compatibility library for term manipulation  predicates. Most predicates
   76in this library are provided as SWI-Prolog built-ins.
   77
   78@compat YAP, SICStus, Quintus.  Not all versions of this library define
   79        exactly the same set of predicates, but defined predicates are
   80        compatible.
   81*/
   82
   83%!  term_size(@Term, -Size) is det.
   84%
   85%   True if Size is the size  in   _cells_  occupied  by Term on the
   86%   global (term) stack. A _cell_ is 4  bytes on 32-bit machines and
   87%   8 bytes on 64-bit machines. The  calculation does take _sharing_
   88%   into account. For example:
   89%
   90%   ```
   91%   ?- A = a(1,2,3), term_size(A,S).
   92%   S = 4.
   93%   ?- A = a(1,2,3), term_size(a(A,A),S).
   94%   S = 7.
   95%   ?- term_size(a(a(1,2,3), a(1,2,3)), S).
   96%   S = 11.
   97%   ```
   98%
   99%   Note that small objects such as atoms  and small integers have a
  100%   size 0. Space is allocated for   floats, large integers, strings
  101%   and compound terms.
  102
  103term_size(Term, Size) :-
  104    '$term_size'(Term, _, Size).
  105
  106%!  variant(@Term1, @Term2) is semidet.
  107%
  108%   Same as SWI-Prolog =|Term1 =@= Term2|=.
  109
  110variant(X, Y) :-
  111    X =@= Y.
  112
  113%!  subsumes_chk(@Generic, @Specific)
  114%
  115%   True if Generic can be made equivalent to Specific without
  116%   changing Specific.
  117%
  118%   @deprecated Replace by subsumes_term/2.
  119
  120subsumes_chk(Generic, Specific) :-
  121    subsumes_term(Generic, Specific).
  122
  123%!  subsumes(+Generic, @Specific)
  124%
  125%   True  if  Generic  is  unified   to  Specific  without  changing
  126%   Specific.
  127%
  128%   @deprecated It turns out that calls to this predicate almost
  129%   always should have used subsumes_term/2.  Also the name is
  130%   misleading.  In case this is really needed, one is adviced to
  131%   follow subsumes_term/2 with an explicit unification.
  132
  133subsumes(Generic, Specific) :-
  134    subsumes_term(Generic, Specific),
  135    Generic = Specific.
  136
  137%!  term_subsumer(+Special1, +Special2, -General) is det.
  138%
  139%   General is the most specific term   that  is a generalisation of
  140%   Special1 and Special2. The  implementation   can  handle  cyclic
  141%   terms.
  142%
  143%   @compat SICStus
  144%   @author Inspired by LOGIC.PRO by Stephen Muggleton
  145
  146%       It has been rewritten by  Jan   Wielemaker  to use the YAP-based
  147%       red-black-trees as mapping rather than flat  lists and use arg/3
  148%       to map compound terms rather than univ and lists.
  149
  150term_subsumer(S1, S2, G) :-
  151    cyclic_term(S1),
  152    cyclic_term(S2),
  153    !,
  154    rb_empty(Map),
  155    lgg_safe(S1, S2, G, Map, _).
  156term_subsumer(S1, S2, G) :-
  157    rb_empty(Map),
  158    lgg(S1, S2, G, Map, _).
  159
  160lgg(S1, S2, G, Map0, Map) :-
  161    (   S1 == S2
  162    ->  G = S1,
  163        Map = Map0
  164    ;   compound(S1),
  165        compound(S2),
  166        functor(S1, Name, Arity),
  167        functor(S2, Name, Arity)
  168    ->  functor(G, Name, Arity),
  169        lgg(0, Arity, S1, S2, G, Map0, Map)
  170    ;   rb_lookup(S1+S2, G0, Map0)
  171    ->  G = G0,
  172        Map = Map0
  173    ;   rb_insert(Map0, S1+S2, G, Map)
  174    ).
  175
  176lgg(Arity, Arity, _, _, _, Map, Map) :- !.
  177lgg(I0, Arity, S1, S2, G, Map0, Map) :-
  178    I is I0 + 1,
  179    arg(I, S1, Sa1),
  180    arg(I, S2, Sa2),
  181    arg(I, G, Ga),
  182    lgg(Sa1, Sa2, Ga, Map0, Map1),
  183    lgg(I, Arity, S1, S2, G, Map1, Map).
  184
  185
  186%!  lgg_safe(+S1, +S2, -G, +Map0, -Map) is det.
  187%
  188%   Cycle-safe version of the  above.  The   difference  is  that we
  189%   insert compounds into the mapping table   and  check the mapping
  190%   table before going into a compound.
  191
  192lgg_safe(S1, S2, G, Map0, Map) :-
  193    (   S1 == S2
  194    ->  G = S1,
  195        Map = Map0
  196    ;   rb_lookup(S1+S2, G0, Map0)
  197    ->  G = G0,
  198        Map = Map0
  199    ;   compound(S1),
  200        compound(S2),
  201        functor(S1, Name, Arity),
  202        functor(S2, Name, Arity)
  203    ->  functor(G, Name, Arity),
  204        rb_insert(Map0, S1+S2, G, Map1),
  205        lgg_safe(0, Arity, S1, S2, G, Map1, Map)
  206    ;   rb_insert(Map0, S1+S2, G, Map)
  207    ).
  208
  209lgg_safe(Arity, Arity, _, _, _, Map, Map) :- !.
  210lgg_safe(I0, Arity, S1, S2, G, Map0, Map) :-
  211    I is I0 + 1,
  212    arg(I, S1, Sa1),
  213    arg(I, S2, Sa2),
  214    arg(I, G, Ga),
  215    lgg_safe(Sa1, Sa2, Ga, Map0, Map1),
  216    lgg_safe(I, Arity, S1, S2, G, Map1, Map).
  217
  218
  219%!  term_factorized(+Term, -Skeleton, -Substiution)
  220%
  221%   Is true when Skeleton is  Term   where  all subterms that appear
  222%   multiple times are replaced by a  variable and Substitution is a
  223%   list of Var=Value that provides the subterm at the location Var.
  224%   I.e., After unifying all substitutions  in Substiutions, Term ==
  225%   Skeleton. Term may be cyclic. For example:
  226%
  227%     ==
  228%     ?- X = a(X), term_factorized(b(X,X), Y, S).
  229%     Y = b(_G255, _G255),
  230%     S = [_G255=a(_G255)].
  231%     ==
  232
  233term_factorized(Term, Skeleton, Substitutions) :-
  234    rb_new(Map0),
  235    add_map(Term, Map0, Map),
  236    rb_visit(Map, Counts),
  237    common_terms(Counts, Common),
  238    (   Common == []
  239    ->  Skeleton = Term,
  240        Substitutions = []
  241    ;   ord_list_to_rbtree(Common, SubstAssoc),
  242        insert_vars(Term, Skeleton, SubstAssoc),
  243        mk_subst(Common, Substitutions, SubstAssoc)
  244    ).
  245
  246add_map(Term, Map0, Map) :-
  247    (   primitive(Term)
  248    ->  Map = Map0
  249    ;   rb_update(Map0, Term, Old, New, Map)
  250    ->  New is Old+1
  251    ;   rb_insert(Map0, Term, 1, Map1),
  252        assoc_arg_map(1, Term, Map1, Map)
  253    ).
  254
  255assoc_arg_map(I, Term, Map0, Map) :-
  256    arg(I, Term, Arg),
  257    !,
  258    add_map(Arg, Map0, Map1),
  259    I2 is I + 1,
  260    assoc_arg_map(I2, Term, Map1, Map).
  261assoc_arg_map(_, _, Map, Map).
  262
  263primitive(Term) :-
  264    var(Term),
  265    !.
  266primitive(Term) :-
  267    atomic(Term),
  268    !.
  269primitive('$VAR'(_)).
  270
  271common_terms([], []).
  272common_terms([H-Count|T], List) :-
  273    !,
  274    (   Count == 1
  275    ->  common_terms(T, List)
  276    ;   List = [H-_NewVar|Tail],
  277        common_terms(T, Tail)
  278    ).
  279
  280insert_vars(T0, T, _) :-
  281    primitive(T0),
  282    !,
  283    T = T0.
  284insert_vars(T0, T, Subst) :-
  285    rb_lookup(T0, S, Subst),
  286    !,
  287    T = S.
  288insert_vars(T0, T, Subst) :-
  289    functor(T0, Name, Arity),
  290    functor(T,  Name, Arity),
  291    insert_arg_vars(1, T0, T, Subst).
  292
  293insert_arg_vars(I, T0, T, Subst) :-
  294    arg(I, T0, A0),
  295    !,
  296    arg(I, T,  A),
  297    insert_vars(A0, A, Subst),
  298    I2 is I + 1,
  299    insert_arg_vars(I2, T0, T, Subst).
  300insert_arg_vars(_, _, _, _).
  301
  302mk_subst([], [], _).
  303mk_subst([Val0-Var|T0], [Var=Val|T], Subst) :-
  304    functor(Val0, Name, Arity),
  305    functor(Val,  Name, Arity),
  306    insert_arg_vars(1, Val0, Val, Subst),
  307    mk_subst(T0, T, Subst).
  308
  309
  310%!  mapargs(:Goal, ?Term1, ?Term2)
  311%
  312%   Term1 and Term2 have the  same   functor  (name/arity)  and for each
  313%   matching pair of arguments call(Goal, A1, A2) is true.
  314
  315mapargs(Goal, Term1, Term2) :-
  316    same_functor(Term1, Term2, Arity),
  317    mapargs_(1, Arity, Goal, Term1, Term2).
  318
  319mapargs_(I, Arity, Goal, Term1, Term2) :-
  320    I =< Arity,
  321    !,
  322    arg(I, Term1, A1),
  323    arg(I, Term2, A2),
  324    call(Goal, A1, A2),
  325    I2 is I+1,
  326    mapargs_(I2, Arity, Goal, Term1, Term2).
  327mapargs_(_, _, _, _, _).
  328
  329
  330%!  mapsubterms(:Goal, +Term1, -Term2) is det.
  331%
  332%   Recursively map sub terms of Term1 into  subterms of Term2 for every
  333%   pair for which call(Goal,  ST1,   ST2)  succeeds.  Procedurably, the
  334%   mapping for each (sub) term pair `T1/T2` is defined as:
  335%
  336%     - If `T1` is a variable, Unify `T2` with `T1`.
  337%     - If call(Goal, T1, T2) succeeds we are done.  Note that the
  338%       mapping does not continue in `T2`.  If this is desired, `Goal`
  339%       must call mapsubterms/3 explicitly as part of it conversion.
  340%     - If `T1` is a dict, map all values, i.e., the _tag_ and _keys_
  341%       are left untouched.
  342%     - If `T1` is a list, map all elements, i.e., the list structure
  343%       is left untouched.
  344%     - If `T1` is a compound, use same_functor/3 to instantiate `T2`
  345%       and recurse over the term arguments left to right.
  346%     - Otherwise `T2` is unified with `T1`.
  347
  348mapsubterms(_Goal, Term1, Term2) :-
  349    var(Term1),
  350    !,
  351    Term2 = Term1.
  352mapsubterms(Goal, Term1, Term2) :-
  353    call(Goal, Term1, Term2),
  354    !.
  355mapsubterms(Goal, Term1, Term2) :-
  356    is_dict(Term1),
  357    !,
  358    dict_pairs(Term1, Tag, Pairs1),
  359    map_dict_pairs(Pairs1, Pairs2, Goal),
  360    dict_pairs(Term2, Tag, Pairs2).
  361mapsubterms(Goal, Term1, Term2) :-
  362     is_list(Term1),
  363     !,
  364     map_list_terms(Term1, Term2, Goal).
  365mapsubterms(Goal, Term1, Term2) :-
  366    compound(Term1),
  367    !,
  368    same_functor(Term1, Term2, Arity),
  369    mapsubterms_(1, Arity, Goal, Term1, Term2).
  370mapsubterms(_, Term, Term).
  371
  372map_dict_pairs([], [], _).
  373map_dict_pairs([K-V0|T0], [K-V|T], Goal) :-
  374    mapsubterms(Goal, V0, V),
  375    map_dict_pairs(T0, T, Goal).
  376
  377map_list_terms([], [], _Goal).
  378map_list_terms([H0|T0], [H|T], Goal) :-
  379    mapsubterms(Goal, H0, H),
  380    map_list_terms(T0, T, Goal).
  381
  382mapsubterms_(I, Arity, Goal, Term1, Term2) :-
  383    I =< Arity,
  384    !,
  385    arg(I, Term1, A1),
  386    arg(I, Term2, A2),
  387    mapsubterms(Goal, A1, A2),
  388    I2 is I+1,
  389    mapsubterms_(I2, Arity, Goal, Term1, Term2).
  390mapsubterms_(_, _, _, _, _).
  391
  392
  393%!  same_functor(?Term1, ?Term2) is semidet.
  394%!  same_functor(?Term1, ?Term2, -Arity) is semidet.
  395%!  same_functor(?Term1, ?Term2, ?Name, ?Arity) is semidet.
  396%
  397%   True when Term1 and Term2  are  terms   that  have  the same functor
  398%   (Name/Arity). The arguments must be sufficiently instantiated, which
  399%   means either Term1 or Term2 must  be   bound  or both Name and Arity
  400%   must be bound.
  401%
  402%   If  Arity  is  0,  Term1  and  Term2   are  unified  with  Name  for
  403%   compatibility.
  404%
  405%   @compat SICStus
  406
  407same_functor(Term1, Term2) :-
  408    same_functor(Term1, Term2, _Name, _Arity).
  409
  410same_functor(Term1, Term2, Arity) :-
  411    same_functor(Term1, Term2, _Name, Arity).
  412
  413same_functor(Term1, Term2, Name, Arity) :-
  414    (   nonvar(Term1)
  415    ->  functor(Term1, Name, Arity, Type),
  416        functor(Term2, Name, Arity, Type)
  417    ;   nonvar(Term2)
  418    ->  functor(Term2, Name, Arity, Type),
  419        functor(Term1, Name, Arity, Type)
  420    ;   functor(Term2, Name, Arity),
  421        functor(Term1, Name, Arity)
  422    )