It is a matter of style whether to use the first or second variant. For simple iterations, the do loop is usually more elegant. We can also often use it inline, and avoid introducing a new predicate name just to perform some iteration.
/* version 1 */ :-mode iteration(+). iteration(L):- (foreach(X,L) do q(X) ). /* version 2 */ :-mode iteration(+). iteration([]). iteration([H|T]):- q(H), iteration(T).
:-mode iteration(+,+). iteration(L,K):- (foreach(X,L), foreach(Y,K) do q(X,Y) ).This requires that the lists are of the same length, otherwise this do loop will fail.
Note that we can put as many parallel operations into a do loop as we want, they are all executed inside one big loop. We can of course also nest do loops so that one loop is executed inside another loop.
The foreach operator can also be used to create a list in a do loop. This is shown in the transformation concept.
Very often, we have to pass additional parameters into the do loop. We do this with the param parameter, which lists all variables from outside the loop that we want to use inside the loop. A variable which is not mentioned as a param argument, is unbound inside the loop. Normally, this will create a warning about a singleton variable inside a do loop. The following code fragment shows the use of param to pass variables A, B and C to the call of predicate q.
:-mode iteration(+,+,+,+). iteration(L,A,B,C):- (foreach(X,L), param(A,B,C) do q(X,A,B,C) ).
% set the group fields inside the interfaces for each interface :-mode set_group_of_interfaces(+,+). set_group_of_interfaces(L,Interfaces):- (foreach(group with [type:Type, name:Name, interface:I],L), param(Interfaces) do find_interface(I,Interfaces,Interface), set_group_of_interface(Type,Name,Interface) ).Here we use the information that each member of the list L is a term group/4 to replace the formal parameter with a term structure where we access individual fields directly. Also note that the body of the loop may contain more than one predicate call.