
+IterationSpecs do +Goals

   Execute Goals iteratively according to IterationSpecs.



Arguments
   +IterationSpecs     a comma-separated sequence of iteration specifiers
   +Goal               a goal (atom or compound term)

Type
   Control

Description

    This is a meta-predicate for writing simple iterations without
    the need for an auxiliary recursive predicate.

    A do-loop corresponds to a call to an auxiliary recursive
    predicate of the form
	do__n(...).
	do__n(...) :- Goals, do__n(...).
    IterationSpecs is one (or a comma-separated sequence) of the following:
    
    fromto(First,In,Out,Last)
    	iterate Goals starting with In=First until Out=Last.
	In and Out are local variables in Goals.

    foreach(X,List)
    	iterate Goals with X ranging over all elements of List.
	X is a local variable in Goals.
	Can also be used for constructing a list.

    foreacharg(X,StructOrArray)
    	iterate Goals with X ranging over all arguments of StructOrArray.
	X is a local variable in Goals.
	Cannot be used for constructing a term.

    for(I,MinExpr,MaxExpr)
	iterate Goals with I ranging over integers from MinExpr to
	MaxExpr.  I is a local variable in Goals.  MinExpr and MaxExpr
	can be arithmetic expressions.  Can be used only for
	controlling iteration, ie.  MaxExpr cannot be uninstantiated. 

    for(I,MinExpr,MaxExpr,Increment) 
	same as before, but Increment can be specified (it defaults to 1). 

    count(I,Min,Max)
    	iterate Goals with I ranging over integers from Min up to Max.
	I is a local variable in Goals.
	Can be used for controlling iteration as well as counting,
	ie. Max can be a variable.

    param(Var1,Var2,...)
    	for declaring variables in Goals global, ie shared with the context.
	CAUTION: By default, variables in Goals are local!
    
    Note that fromto/4 is the most general specifier, but foreach/2,
    foreacharg/2, count/3, for/3,4 and param/N are convenient shorthands.
    
    Syntax: The do-operator binds like the semicolon, ie. less than comma.
    That means that the whole do-construct should always be bracketed.
    
    Unless you use :-pragma(noexpand) or :-dbgcomp, the do-construct is
    compiled into an efficient auxiliary predicate named do__nnn, where
    nnn is a unique integer.


Resatisfiable
      No.

Fail Conditions
      Fails if one of the Goals fails, or if two IterationSpecs
   specify a different number of iterations.



Exceptions
     4 --- IterationSpecs insufficiently instantiated
   100 --- Ill-formed IterationSpecs

Examples
   
% iterate over list
?- (foreach(X,[1,2,3]) do writeln(X)).

% maplist
?- (foreach(X,[1,2,3]), foreach(Y,List) do Y is X+3).

% sumlist
?- (foreach(X,[1,2,3]), fromto(0,In,Out,Sum) do Out is In+X).

% reverse list
?- (foreach(X,[1,2,3]), fromto([],In,Out,   Rev) do Out=[X|In]).

% reverse list (even shorter)
?- (foreach(X,[1,2,3]), fromto([],In,[X|In],Rev) do true).

% iterate over integers from 1 up to 5
?- (for(I,1,5) do writeln(I)).

% iterate over integers from 1 up to 5
?- (count(I,1,5) do writeln(I)).

% make list of integers [1,2,3,4,5]
?- (for(I,1,5), foreach(I,List) do true).

% make a list of length 3
?- (foreach(_,List), for(_,1,3) do true).

% get the length of a list
?- (foreach(_,[a,b,c]), count(_,1,N) do true).

% actually, the length/2 builtin is (almost)
length(List, N) :- (foreach(_,List), count(_,1,N) do true).

% filter list elements
?- (foreach(X,[5,3,8,1,4,6]), fromto(List,Out,In,[]) do
    X>3 -> Out=[X|In] ; Out=In).

% iterate over structure arguments
?- (foreacharg(X,s(a,b,c,d,e)) do writeln(X)).

% collect args in list
% (bad example, use =.. if you really want to do that!)
?- (foreacharg(X,s(a,b,c,d,e)), foreach(X,List) do true).

% collect args reverse
?- (foreacharg(X,s(a,b,c,d,e)), fromto([],In,[X|In],List) do true).

% or like this:
?- S = s(a,b,c,d,e), functor(S, _, N),
    (for(I,N,1,-1), foreach(A,List), param(S) do arg(I,S,A)).

% The following two are equivalent
?- (foreach(X,[1,2,3])        do             writeln(X)).
?- (fromto([1,2,3],In,Out,[]) do In=[X|Out], writeln(X)).

% The following two are equivalent
?- (count(I,1,5)     do            writeln(I)).
?- (fromto(0,I0,I,5) do I is I0+1, writeln(I)).


% Two examples for nested loops. Print all pairs of list elements:
?- Xs = [1,2,3,4],
    ( foreach(X, Xs), param(Xs) do
	( foreach(Y,Xs), param(X) do
	    writeln(X-Y)
	)
    ).

% and the same without symmetries:
?- Xs = [1,2,3,4],
    ( fromto(Xs, [X|Xs1], Xs1, []) do
	( foreach(Y,Xs1), param(X) do
	    writeln(X-Y)
	)
    ).


% Find all pairs of list elements and collect them in a result list:

pairs(Xs, Ys, Zs) :-
    (
        foreach(X,Xs),
        fromto(Zs, Zs4, Zs1, []),
        param(Ys)
    do
        (
            foreach(Y,Ys),
            fromto(Zs4, Zs3, Zs2, Zs1),
            param(X)
        do
            Zs3 = [X-Y|Zs2]
        )
    ).


# flatten a 2-dimensional matrix into a list

flatten_matrix(Mat, Xs) :-
	dim(Mat, [M,N]),
	(
	    for(I,1,M),
	    fromto(Xs, Xs4, Xs1, []),
	    param(Mat,N)
	do
	    (
		for(J,1,N),
		fromto(Xs4, [X|Xs2], Xs2, Xs1),
		param(Mat,I)
	    do
	    	X is Mat[I,J]
	    )
	).


See Also
   pragma / 1
