Cautions on the use

The built-in foreach and the list comprehension notation are powerful means for describing repetition. When a program is compiled, calls to foreach are converted into calls to internally generated tail-recursive predicates and list comprehensions are converted into calls to foreach with accumulators. Therefore, loop constructs almost incur no penalty on the performance compared with recursion. Nevertheless, the user must take the following cautions in using them to avoid unanticipated behavior.

Firstly, iterators are matching-based. No iterator can change a collection unless the goal of the loop has that effect. For example,

   ?-foreach(f(a,X) in [c,f(a,b),f(Y,Z)],write(X)).
displays b. The elements c and f(Y,Z) are skipped because they do not match the pattern f(a,X).

Secondly, variables are assumed to be global to all the iterations unless they are declared local or occur in the patterns of the iterators. Sometimes, one may use anonymous variables '_' in looping goals and wrongly believe that they are local. The parser issues a warning when it encounters a variable that is not declared local but occurs alone a looping goal.

Thirdly, no meta terms should be included in iterators or list constructors! For example,

   ?-D=1..5, foreach(X in D, write(X)).
is bad since D is a meta term. As another example,
   ?-C=(X : I in 1..5), L @=[C].
is bad since C is a meta term. When meta terms are included in iterators or list constructors, the compiler may generate code that has different behavior as interpreted.

Neng-Fa Zhou 2012-01-03