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-2024, University of Amsterdam
    7                              VU University Amsterdam
    8                              CWI Amsterdam
    9                              SWI-Prolog Solutions b.v.
   10    All rights reserved.
   11
   12    Redistribution and use in source and binary forms, with or without
   13    modification, are permitted provided that the following conditions
   14    are met:
   15
   16    1. Redistributions of source code must retain the above copyright
   17       notice, this list of conditions and the following disclaimer.
   18
   19    2. Redistributions in binary form must reproduce the above copyright
   20       notice, this list of conditions and the following disclaimer in
   21       the documentation and/or other materials provided with the
   22       distribution.
   23
   24    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   25    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   26    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   27    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   28    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   29    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   30    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   31    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   32    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   34    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   35    POSSIBILITY OF SUCH DAMAGE.
   36*/
   37
   38:- module(aggregate,
   39          [ aggregate/3,                % +Templ, :Goal, -Result
   40            aggregate/4,                % +Templ, +Discrim, :Goal, -Result
   41            aggregate_all/3,            % +Templ, :Goal, -Result
   42            aggregate_all/4,            % +Templ, +Discrim, :Goal, -Result
   43            foldall/4,			% :Folder, :Goal, +V0, -V)
   44            foreach/2,                  % :Generator, :Goal
   45            free_variables/4            % :Generator, :Template, +Vars0, -Vars
   46          ]).   47:- autoload(library(apply),[maplist/4,maplist/5]).   48:- autoload(library(error),
   49	    [instantiation_error/1,type_error/2,domain_error/2]).   50:- autoload(library(lists),
   51	    [append/3,member/2,sum_list/2,max_list/2,min_list/2]).   52:- autoload(library(ordsets),[ord_intersection/3]).   53:- autoload(library(pairs),[pairs_values/2]).   54:- autoload(library(prolog_code), [mkconj/3]).   55
   56:- set_prolog_flag(generate_debug_info, false).   57
   58:- meta_predicate
   59    aggregate(?,^,-),
   60    aggregate(?,?,^,-),
   61    aggregate_all(?,0,-),
   62    aggregate_all(?,?,0,-),
   63    foldall(2,0,+,-),
   64    foreach(0,0).   65
   66/** <module> Aggregation operators on backtrackable predicates
   67
   68This library provides aggregating operators  over   the  solutions  of a
   69predicate. The operations are a generalisation   of the bagof/3, setof/3
   70and findall/3 built-in predicates.  Aggregations   that  can be computed
   71incrementally avoid findall/3 and run in   constant  memory. The defined
   72aggregation  operations  are  counting,  computing   the  sum,  minimum,
   73maximum, a bag of solutions and a  set   of  solutions.  We first give a
   74simple example, computing the country with the smallest area:
   75
   76```
   77smallest_country(Name, Area) :-
   78    aggregate(min(A, N), country(N, A), min(Area, Name)).
   79```
   80
   81There  are  four  aggregation    predicates  (aggregate/3,  aggregate/4,
   82aggregate_all/3 and aggregate/4), distinguished on two properties.
   83
   84    - aggregate vs. aggregate_all <br>
   85      The aggregate predicates use setof/3 (aggregate/4) or bagof/3
   86      (aggregate/3), dealing with existential qualified variables
   87      (`Var^Goal`) and providing multiple solutions for the remaining
   88      free variables in `Goal`. The aggregate_all/3 predicate uses
   89      findall/3, implicitly qualifying all free variables and providing
   90      exactly one solution, while aggregate_all/4 uses sort/2 over
   91      solutions that Discriminator (see below) generated using
   92      findall/3.
   93
   94    - The Discriminator argument <br>
   95      The versions with 4 arguments deduplicate redundant solutions of
   96      Goal. Solutions for which both the template variables and
   97      Discriminator are identical will be treated as one solution. For
   98      example, if we wish to compute the total population of all
   99      countries, and for some reason =|country(belgium, 11000000)|= may
  100      succeed twice, we can use the following to avoid counting the
  101      population of Belgium twice:
  102
  103          aggregate(sum(P), Name, country(Name, P), Total)
  104
  105All aggregation predicates support  the   following  operators  below in
  106Template. In addition, they allow for  an arbitrary named compound term,
  107where each of the arguments is a term  from the list below. For example,
  108the term r(min(X), max(X)) computes both the minimum and maximum binding
  109for X.
  110
  111  - count
  112    Count number of solutions.  Same as sum(1).
  113  - sum(Expr)
  114    Sum of Expr for all solutions.
  115  - min(Expr)
  116    Minimum of Expr for all solutions.
  117  - min(Expr, Witness)
  118    A term min(Min, Witness), where Min is the minimal version of
  119    Expr over all solutions, and Witness is any other template
  120    applied to solutions that produced Min. If multiple solutions
  121    provide the same minimum, Witness corresponds to the first
  122    solution.
  123  - max(Expr)
  124    Maximum of Expr for all solutions.
  125  - max(Expr, Witness)
  126    As min(Expr, Witness), but producing the maximum result.
  127  - set(X)
  128    An ordered set with all solutions for X.
  129  - bag(X)
  130    A list of all solutions for X.
  131
  132__Acknowledgements__
  133
  134_|The development of this library was sponsored by SecuritEase,
  135  http://www.securitease.com
  136|_
  137
  138@compat Quintus, SICStus 4. The forall/2 is a SWI-Prolog built-in and
  139        term_variables/3 is a SWI-Prolog built-in with
  140        __different semantics__.  The foldall/4 primitive is a
  141        SWI-Prolog addition.
  142@tbd    Analysing the aggregation template and compiling a predicate
  143        for the list aggregation can be done at compile time.
  144@tbd    aggregate_all/3 can be rewritten to run in constant space using
  145        non-backtrackable assignment on a term.
  146*/
  147
  148                 /*******************************
  149                 *           AGGREGATE          *
  150                 *******************************/
  151
  152%!  aggregate(+Template, :Goal, -Result) is nondet.
  153%
  154%   Aggregate bindings in Goal according to Template.  The aggregate/3
  155%   version performs bagof/3 on Goal.
  156
  157aggregate(Template, Goal0, Result) :-
  158    template_to_pattern(bag, Template, Pattern, Goal0, Goal, Aggregate),
  159    bagof(Pattern, Goal, List),
  160    aggregate_list(Aggregate, List, Result).
  161
  162%!  aggregate(+Template, +Discriminator, :Goal, -Result) is nondet.
  163%
  164%   Aggregate bindings in Goal according to Template.  The aggregate/4
  165%   version performs setof/3 on Goal.
  166
  167aggregate(Template, Discriminator, Goal0, Result) :-
  168    template_to_pattern(bag, Template, Pattern, Goal0, Goal, Aggregate),
  169    setof(Discriminator-Pattern, Goal, Pairs),
  170    pairs_values(Pairs, List),
  171    aggregate_list(Aggregate, List, Result).
  172
  173%!  aggregate_all(+Template, :Goal, -Result) is semidet.
  174%
  175%   Aggregate   bindings   in   Goal   according    to   Template.   The
  176%   aggregate_all/3 version performs findall/3 on   Goal. Note that this
  177%   predicate fails if Template contains one  or more of min(X), max(X),
  178%   min(X,Witness) or max(X,Witness) and Goal   has  no solutions, i.e.,
  179%   the minimum and maximum of an empty set is undefined.
  180%
  181%   The Template values `count`, sum(X),   max(X),  min(X), max(X,W) and
  182%   min(X,W) are processed incrementally rather than using findall/3 and
  183%   run in constant memory.
  184%
  185%   @see foldall/4 to "fold" over all answers.
  186
  187aggregate_all(Var, _, _) :-
  188    var(Var),
  189    !,
  190    instantiation_error(Var).
  191aggregate_all(count, Goal, Count) :-
  192    !,
  193    aggregate_all(sum(1), Goal, Count).
  194aggregate_all(sum(X), Goal, Sum) :-
  195    !,
  196    State = state(0),
  197    (  call(Goal),
  198           arg(1, State, S0),
  199           S is S0 + X,
  200           nb_setarg(1, State, S),
  201           fail
  202    ;  arg(1, State, Sum)
  203    ).
  204aggregate_all(max(X), Goal, Max) :-
  205    !,
  206    State = state(X),
  207    (  call(Goal),
  208           arg(1, State, M0),
  209           M is max(M0,X),
  210           nb_setarg(1, State, M),
  211           fail
  212    ;  arg(1, State, Max),
  213       nonvar(Max)
  214    ).
  215aggregate_all(min(X), Goal, Min) :-
  216    !,
  217    State = state(X),
  218    (  call(Goal),
  219           arg(1, State, M0),
  220           M is min(M0,X),
  221           nb_setarg(1, State, M),
  222           fail
  223    ;  arg(1, State, Min),
  224       nonvar(Min)
  225    ).
  226aggregate_all(max(X,W), Goal, max(Max,Witness)) :-
  227    !,
  228    State = state(false, _Max, _Witness),
  229    (  call(Goal),
  230           (   State = state(true, Max0, _)
  231           ->  X > Max0,
  232               nb_setarg(2, State, X),
  233               nb_setarg(3, State, W)
  234           ;   number(X)
  235           ->  nb_setarg(1, State, true),
  236               nb_setarg(2, State, X),
  237               nb_setarg(3, State, W)
  238           ;   type_error(number, X)
  239           ),
  240           fail
  241    ;  State = state(true, Max, Witness)
  242    ).
  243aggregate_all(min(X,W), Goal, min(Min,Witness)) :-
  244    !,
  245    State = state(false, _Min, _Witness),
  246    (  call(Goal),
  247           (   State = state(true, Min0, _)
  248           ->  X < Min0,
  249               nb_setarg(2, State, X),
  250               nb_setarg(3, State, W)
  251           ;   number(X)
  252           ->  nb_setarg(1, State, true),
  253               nb_setarg(2, State, X),
  254               nb_setarg(3, State, W)
  255           ;   type_error(number, X)
  256           ),
  257           fail
  258    ;  State = state(true, Min, Witness)
  259    ).
  260aggregate_all(Template, Goal0, Result) :-
  261    template_to_pattern(all, Template, Pattern, Goal0, Goal, Aggregate),
  262    findall(Pattern, Goal, List),
  263    aggregate_list(Aggregate, List, Result).
  264
  265%!  aggregate_all(+Template, +Discriminator, :Goal, -Result) is semidet.
  266%
  267%   Aggregate  bindings  in  Goal   according    to   Template.  The
  268%   aggregate_all/4 version performs findall/3 followed by sort/2 on
  269%   Goal. See aggregate_all/3 to understand   why this predicate can
  270%   fail.
  271
  272aggregate_all(Template, Discriminator, Goal0, Result) :-
  273    template_to_pattern(all, Template, Pattern, Goal0, Goal, Aggregate),
  274    findall(Discriminator-Pattern, Goal, Pairs0),
  275    sort(Pairs0, Pairs),
  276    pairs_values(Pairs, List),
  277    aggregate_list(Aggregate, List, Result).
  278
  279template_to_pattern(All, Template, Pattern, Goal0, Goal, Aggregate) :-
  280    template_to_pattern(Template, Pattern, Post, Vars, Aggregate),
  281    existential_vars(Goal0, Goal1, AllVars, Vars),
  282    clean_body((Goal1, Post), Goal2),
  283    (   All == bag
  284    ->  add_existential_vars(AllVars, Goal2, Goal)
  285    ;   Goal = Goal2
  286    ).
  287
  288existential_vars(Var, Var) -->
  289    { var(Var) },
  290    !.
  291existential_vars(Var^G0, G) -->
  292    !,
  293    [Var],
  294    existential_vars(G0, G).
  295existential_vars(M:G0, M:G) -->
  296    !,
  297    existential_vars(G0, G).
  298existential_vars(G, G) -->
  299    [].
  300
  301add_existential_vars([], G, G).
  302add_existential_vars([H|T], G0, H^G1) :-
  303    add_existential_vars(T, G0, G1).
  304
  305
  306%!  clean_body(+Goal0, -Goal) is det.
  307%
  308%   Remove redundant `true` from Goal0.
  309
  310clean_body((Goal0,Goal1), Goal) =>
  311    clean_body(Goal0, GoalA),
  312    clean_body(Goal1, GoalB),
  313    mkconj(GoalA, GoalB, Goal).
  314clean_body(Goal0, Goal) =>
  315    Goal = Goal0.
  316
  317
  318%!  template_to_pattern(+Template, -Pattern, -Post, -Vars, -Aggregate)
  319%
  320%   Determine which parts of the goal we must remember in the
  321%   findall/3 pattern.
  322%
  323%   @arg Post is a body-term that evaluates expressions to reduce
  324%               storage requirements.
  325%   @arg Vars is a list of intermediate variables that must be
  326%               added to the existential variables for bagof/3.
  327%   @arg Aggregate defines the aggregation operation to execute.
  328
  329template_to_pattern(Term, Pattern, Goal, Vars, Aggregate) :-
  330    templ_to_pattern(Term, Pattern, Goal, Vars, Aggregate),
  331    !.
  332template_to_pattern(Term, Pattern, Goal, Vars, term(MinNeeded, Functor, AggregateArgs)) :-
  333    compound(Term),
  334    !,
  335    Term =.. [Functor|Args0],
  336    templates_to_patterns(Args0, Args, Goal, Vars, AggregateArgs),
  337    needs_one(AggregateArgs, MinNeeded),
  338    Pattern =.. [Functor|Args].
  339template_to_pattern(Term, _, _, _, _) :-
  340    invalid_template(Term).
  341
  342templ_to_pattern(sum(X),           X,         true,    [],   sum) :- var(X), !.
  343templ_to_pattern(sum(X0),          X,         X is X0, [X0], sum) :- !.
  344templ_to_pattern(count,            1,         true,    [],   count) :- !.
  345templ_to_pattern(min(X),           X,         true,    [],   min) :- var(X), !.
  346templ_to_pattern(min(X0),          X,         X is X0, [X0], min) :- !.
  347templ_to_pattern(min(X0, Witness), X-Witness, X is X0, [X0], min_witness) :- !.
  348templ_to_pattern(max(X0),          X,         X is X0, [X0], max) :- !.
  349templ_to_pattern(max(X0, Witness), X-Witness, X is X0, [X0], max_witness) :- !.
  350templ_to_pattern(set(X),           X,         true,    [],   set) :- !.
  351templ_to_pattern(bag(X),           X,         true,    [],   bag) :- !.
  352
  353templates_to_patterns([], [], true, [], []).
  354templates_to_patterns([H0], [H], G, Vars, [A]) :-
  355    !,
  356    sub_template_to_pattern(H0, H, G, Vars, A).
  357templates_to_patterns([H0|T0], [H|T], (G0,G), Vars, [A0|A]) :-
  358    sub_template_to_pattern(H0, H, G0, V0, A0),
  359    append(V0, RV, Vars),
  360    templates_to_patterns(T0, T, G, RV, A).
  361
  362sub_template_to_pattern(Term, Pattern, Goal, Vars, Aggregate) :-
  363    templ_to_pattern(Term, Pattern, Goal, Vars, Aggregate),
  364    !.
  365sub_template_to_pattern(Term, _, _, _, _) :-
  366    invalid_template(Term).
  367
  368invalid_template(Term) :-
  369    callable(Term),
  370    !,
  371    domain_error(aggregate_template, Term).
  372invalid_template(Term) :-
  373    type_error(aggregate_template, Term).
  374
  375%!  needs_one(+Ops, -OneOrZero)
  376%
  377%   If one of the operations in Ops needs at least one answer,
  378%   unify OneOrZero to 1.  Else 0.
  379
  380needs_one(Ops, 1) :-
  381    member(Op, Ops),
  382    needs_one(Op),
  383    !.
  384needs_one(_, 0).
  385
  386needs_one(min).
  387needs_one(min_witness).
  388needs_one(max).
  389needs_one(max_witness).
  390
  391%!  aggregate_list(+Op, +List, -Answer) is semidet.
  392%
  393%   Aggregate the answer  from  the   list  produced  by  findall/3,
  394%   bagof/3 or setof/3. The latter  two   cases  deal  with compound
  395%   answers.
  396%
  397%   @tbd    Compile code for incremental state update, which we will use
  398%           for aggregate_all/3 as well.  We should be using goal_expansion
  399%           to generate these clauses.
  400
  401aggregate_list(bag, List0, List) :-
  402    !,
  403    List = List0.
  404aggregate_list(set, List, Set) :-
  405    !,
  406    sort(List, Set).
  407aggregate_list(sum, List, Sum) :-
  408    sum_list(List, Sum).
  409aggregate_list(count, List, Count) :-
  410    length(List, Count).
  411aggregate_list(max, List, Sum) :-
  412    max_list(List, Sum).
  413aggregate_list(max_witness, List, max(Max, Witness)) :-
  414    max_pair(List, Max, Witness).
  415aggregate_list(min, List, Sum) :-
  416    min_list(List, Sum).
  417aggregate_list(min_witness, List, min(Min, Witness)) :-
  418    min_pair(List, Min, Witness).
  419aggregate_list(term(0, Functor, Ops), List, Result) :-
  420    !,
  421    maplist(state0, Ops, StateArgs, FinishArgs),
  422    State0 =.. [Functor|StateArgs],
  423    aggregate_term_list(List, Ops, State0, Result0),
  424    finish_result(Ops, FinishArgs, Result0, Result).
  425aggregate_list(term(1, Functor, Ops), [H|List], Result) :-
  426    H =.. [Functor|Args],
  427    maplist(state1, Ops, Args, StateArgs, FinishArgs),
  428    State0 =.. [Functor|StateArgs],
  429    aggregate_term_list(List, Ops, State0, Result0),
  430    finish_result(Ops, FinishArgs, Result0, Result).
  431
  432aggregate_term_list([], _, State, State).
  433aggregate_term_list([H|T], Ops, State0, State) :-
  434    step_term(Ops, H, State0, State1),
  435    aggregate_term_list(T, Ops, State1, State).
  436
  437
  438%!  min_pair(+Pairs, -Key, -Value) is det.
  439%!  max_pair(+Pairs, -Key, -Value) is det.
  440%
  441%   True if Key-Value has the  smallest/largest   key  in  Pairs. If
  442%   multiple pairs share the smallest/largest key, the first pair is
  443%   returned.
  444
  445min_pair([M0-W0|T], M, W) :-
  446    min_pair(T, M0, W0, M, W).
  447
  448min_pair([], M, W, M, W).
  449min_pair([M0-W0|T], M1, W1, M, W) :-
  450    (   M0 < M1
  451    ->  min_pair(T, M0, W0, M, W)
  452    ;   min_pair(T, M1, W1, M, W)
  453    ).
  454
  455max_pair([M0-W0|T], M, W) :-
  456    max_pair(T, M0, W0, M, W).
  457
  458max_pair([], M, W, M, W).
  459max_pair([M0-W0|T], M1, W1, M, W) :-
  460    (   M0 > M1
  461    ->  max_pair(T, M0, W0, M, W)
  462    ;   max_pair(T, M1, W1, M, W)
  463    ).
  464
  465%!  step(+AggregateAction, +New, +State0, -State1).
  466
  467step(bag,   X, [X|L], L).
  468step(set,   X, [X|L], L).
  469step(count, _, X0, X1) :-
  470    succ(X0, X1).
  471step(sum,   X, X0, X1) :-
  472    X1 is X0+X.
  473step(max,   X, X0, X1) :-
  474    X1 is max(X0, X).
  475step(min,   X, X0, X1) :-
  476    X1 is min(X0, X).
  477step(max_witness, X-W, X0-W0, X1-W1) :-
  478    (   X > X0
  479    ->  X1 = X, W1 = W
  480    ;   X1 = X0, W1 = W0
  481    ).
  482step(min_witness, X-W, X0-W0, X1-W1) :-
  483    (   X < X0
  484    ->  X1 = X, W1 = W
  485    ;   X1 = X0, W1 = W0
  486    ).
  487step(term(Ops), Row, Row0, Row1) :-
  488    step_term(Ops, Row, Row0, Row1).
  489
  490step_term(Ops, Row, Row0, Row1) :-
  491    functor(Row, Name, Arity),
  492    functor(Row1, Name, Arity),
  493    step_list(Ops, 1, Row, Row0, Row1).
  494
  495step_list([], _, _, _, _).
  496step_list([Op|OpT], Arg, Row, Row0, Row1) :-
  497    arg(Arg, Row, X),
  498    arg(Arg, Row0, X0),
  499    arg(Arg, Row1, X1),
  500    step(Op, X, X0, X1),
  501    succ(Arg, Arg1),
  502    step_list(OpT, Arg1, Row, Row0, Row1).
  503
  504finish_result(Ops, Finish, R0, R) :-
  505    functor(R0, Functor, Arity),
  506    functor(R, Functor, Arity),
  507    finish_result(Ops, Finish, 1, R0, R).
  508
  509finish_result([], _, _, _, _).
  510finish_result([Op|OpT], [F|FT], I, R0, R) :-
  511    arg(I, R0, A0),
  512    arg(I, R, A),
  513    finish_result1(Op, F, A0, A),
  514    succ(I, I2),
  515    finish_result(OpT, FT, I2, R0, R).
  516
  517finish_result1(bag, Bag0, [], Bag) :-
  518    !,
  519    Bag = Bag0.
  520finish_result1(set, Bag,  [], Set) :-
  521    !,
  522    sort(Bag, Set).
  523finish_result1(max_witness, _, M-W, R) :-
  524    !,
  525    R = max(M,W).
  526finish_result1(min_witness, _, M-W, R) :-
  527    !,
  528    R = min(M,W).
  529finish_result1(_, _, A, A).
  530
  531%!  state0(+Op, -State, -Finish)
  532
  533state0(bag,   L, L).
  534state0(set,   L, L).
  535state0(count, 0, _).
  536state0(sum,   0, _).
  537
  538%!  state1(+Op, +First, -State, -Finish)
  539
  540state1(bag, X, L, [X|L]) :- !.
  541state1(set, X, L, [X|L]) :- !.
  542state1(_,   X, X, _).
  543
  544
  545		 /*******************************
  546		 *             FOLDALL		*
  547		 *******************************/
  548
  549%!  foldall(:Folder, :Goal, +V0, -V) is det.
  550%
  551%   Use Folder to fold V0 to V using all answers of Goal. This predicate
  552%   generates all answers  for  Goal  and   for  each  answer  it  calls
  553%   call(Folder,V0,V1). This predicate  provides   behaviour  similar to
  554%   aggregate_all/3-4, but operates in  constant   space  and allows for
  555%   custom aggregation (Folder) operators. The example below uses plus/3
  556%   to realise aggregate_all(sum(X), between(1,10,X), Sum).
  557%
  558%       ?- foldall(plus(X), between(1,10,X), 0, Sum).
  559%       Sum = 55
  560%
  561%   The implementation uses  nb_setarg/3   for  non-backtrackable  state
  562%   updates.
  563%
  564%   @see aggregate_all/3-4, foldl/4-7, nb_setarg/3.
  565
  566foldall(Op, Goal, V0, V) :-
  567    State = state(V0),
  568    (   call(Goal),
  569          arg(1, State, S0),
  570          call(Op, S0, S),
  571          nb_setarg(1, State, S),
  572          fail
  573    ;   arg(1, State, V)
  574    ).
  575
  576
  577                 /*******************************
  578                 *             FOREACH          *
  579                 *******************************/
  580
  581%!  foreach(:Generator, :Goal)
  582%
  583%   True when the conjunction  of  _instances_   of  Goal  created  from
  584%   solutions for Generator is true. Except for term copying, this could
  585%   be implemented as below.
  586%
  587%   ```
  588%   foreach(Generator, Goal) :-
  589%       findall(Goal, Generator, Goals),
  590%       maplist(call, Goals).
  591%   ```
  592%
  593%   The actual implementation uses findall/3 on  a template created from
  594%   the variables _shared_ between Generator  and Goal. Subsequently, it
  595%   uses every instance of this template  to instantiate Goal, call Goal
  596%   and undo _only_ the instantiation of   the  template and _not_ other
  597%   instantiations created by running Goal.  Here is an example:
  598%
  599%   ```
  600%   ?- foreach(between(1,4,X), dif(X,Y)), Y = 5.
  601%   Y = 5.
  602%   ?- foreach(between(1,4,X), dif(X,Y)), Y = 3.
  603%   false.
  604%   ```
  605%
  606%   The  predicate  foreach/2  is   mostly    used   if   Goal  performs
  607%   backtrackable destructive assignment on  terms. Attributed variables
  608%   (underlying constraints) are  an  example.   Another  example  of  a
  609%   backtrackable data structure is in   library(hashtable).  If we care
  610%   only about the side effects  (I/O,   dynamic  database, etc.) or the
  611%   truth value of Goal,  forall/2 is  a faster and simpler alternative.
  612%   If Goal instantiates its arguments it  is   will  often  fail as the
  613%   argument cannot be instantiated to multiple   values. It is possible
  614%   to incrementally _grow_ an argument:
  615%
  616%   ```
  617%   ?- foreach(between(1,4,X), member(X, L)).
  618%   L = [1,2,3,4|_].
  619%   ```
  620%
  621%   Note that SWI-Prolog up to  version   8.3.4  created  copies of Goal
  622%   using  copy_term/2  for  each  iteration,  this  makes  the  current
  623%   implementation unable to properly handle   compound terms (in Goal's
  624%   arguments) that share variables with the  Generator. As a workaround
  625%   you can define a goal that does not use compound terms, like in this
  626%   example:
  627%
  628%   ```
  629%   mem(E,L) :-  % mem/2 hides the compound argument from foreach/2
  630%      member(r(E),L).
  631%
  632%   ?- foreach(  between(1,5,N), mem(N,L)).
  633%   ```
  634
  635foreach(Generator, Goal) :-
  636    term_variables(Generator, GenVars0), sort(GenVars0, GenVars),
  637    term_variables(Goal, GoalVars0), sort(GoalVars0, GoalVars),
  638    ord_intersection(GenVars, GoalVars, SharedVars),
  639    Templ =.. [v|SharedVars],
  640    findall(Templ, Generator, List),
  641    prove_list(List, Templ, Goal).
  642
  643prove_list([], _, _).
  644prove_list([H|T], Templ, Goal) :-
  645    Templ = H,
  646    call(Goal),
  647    '$unbind_template'(Templ),
  648    prove_list(T, Templ, Goal).
  649
  650
  651%!  free_variables(:Generator, +Template, +VarList0, -VarList) is det.
  652%
  653%   Find free variables in bagof/setof template.  In order to handle
  654%   variables  properly,  we  have  to   find  all  the  universally
  655%   quantified variables in the  Generator.   All  variables  as yet
  656%   unbound are universally quantified, unless
  657%
  658%       1. they occur in the template
  659%       2. they are bound by X^P, setof/3, or bagof/3
  660%
  661%   free_variables(Generator, Template, OldList, NewList) finds this
  662%   set using OldList as an accumulator.
  663%
  664%   @author Richard O'Keefe
  665%   @author Jan Wielemaker (made some SWI-Prolog enhancements)
  666%   @license Public domain (from DEC10 library).
  667%   @tbd Distinguish between control-structures and data terms.
  668%   @tbd Exploit our built-in term_variables/2 at some places?
  669
  670free_variables(Term, Bound, VarList, [Term|VarList]) :-
  671    var(Term),
  672    term_is_free_of(Bound, Term),
  673    list_is_free_of(VarList, Term),
  674    !.
  675free_variables(Term, _Bound, VarList, VarList) :-
  676    var(Term),
  677    !.
  678free_variables(Term, Bound, OldList, NewList) :-
  679    explicit_binding(Term, Bound, NewTerm, NewBound),
  680    !,
  681    free_variables(NewTerm, NewBound, OldList, NewList).
  682free_variables(Term, Bound, OldList, NewList) :-
  683    functor(Term, _, N),
  684    free_variables(N, Term, Bound, OldList, NewList).
  685
  686free_variables(0, _, _, VarList, VarList) :- !.
  687free_variables(N, Term, Bound, OldList, NewList) :-
  688    arg(N, Term, Argument),
  689    free_variables(Argument, Bound, OldList, MidList),
  690    M is N-1,
  691    !,
  692    free_variables(M, Term, Bound, MidList, NewList).
  693
  694%   explicit_binding checks for goals known to existentially quantify
  695%   one or more variables.  In particular \+ is quite common.
  696
  697explicit_binding(\+ _Goal,             Bound, fail,     Bound      ) :- !.
  698explicit_binding(not(_Goal),           Bound, fail,     Bound      ) :- !.
  699explicit_binding(Var^Goal,             Bound, Goal,     Bound+Var) :- !.
  700explicit_binding(setof(Var,Goal,Set),  Bound, Goal-Set, Bound+Var) :- !.
  701explicit_binding(bagof(Var,Goal,Bag),  Bound, Goal-Bag, Bound+Var) :- !.
  702
  703%!  term_is_free_of(+Term, +Var) is semidet.
  704%
  705%   True if Var does not appear  in   Term.  This has been rewritten
  706%   from the DEC10 library source   to exploit our non-deterministic
  707%   arg/3.
  708
  709term_is_free_of(Term, Var) :-
  710    \+ var_in_term(Term, Var).
  711
  712var_in_term(Term, Var) :-
  713    Var == Term,
  714    !.
  715var_in_term(Term, Var) :-
  716    compound(Term),
  717    arg(_, Term, Arg),
  718    var_in_term(Arg, Var),
  719    !.
  720
  721
  722%!  list_is_free_of(+List, +Var) is semidet.
  723%
  724%   True if Var is not in List.
  725
  726list_is_free_of([Head|Tail], Var) :-
  727    Head \== Var,
  728    !,
  729    list_is_free_of(Tail, Var).
  730list_is_free_of([], _).
  731
  732
  733%       term_variables(+Term, +Vars0, -Vars) is det.
  734%
  735%       True if Vars is the union of variables in Term and Vars0.
  736%       We cannot have this as term_variables/3 is already defined
  737%       as a difference-list version of term_variables/2.
  738
  739%term_variables(Term, Vars0, Vars) :-
  740%       term_variables(Term+Vars0, Vars).
  741
  742
  743%!  sandbox:safe_meta(+Goal, -Called) is semidet.
  744%
  745%   Declare the aggregate meta-calls safe. This cannot be proven due
  746%   to the manipulations of the argument Goal.
  747
  748:- multifile sandbox:safe_meta_predicate/1.  749
  750sandbox:safe_meta_predicate(aggregate:foreach/2).
  751sandbox:safe_meta_predicate(aggregate:aggregate/3).
  752sandbox:safe_meta_predicate(aggregate:aggregate/4).
  753sandbox:safe_meta_predicate(aggregate:aggregate_all/3).
  754sandbox:safe_meta_predicate(aggregate:aggregate_all/4)