ForeachTerm : foreach Term do Term end foreach
Consider the schematic foreach term:
foreach Gen do Body end foreach
Gen is (typically) a nondeterm term. Body is evaluated for each solution of Gen. If/when Gen fails the foreach-term succeeds without evaluating Body. Body must be procedure (or erroneous). Gen and Body are both cut scopes.
The schematic foreach term resembles a fail loop:
Gen, Body, fail
The main (and important) difference is that a foreach-term succeeds after the iteration, whereas a fail loop fails. As a result foreach-terms can be followed by other terms and they can be properly nested.
foreach L = list::getMember_nd(LL) do write("<< "), foreach X = list::getMember_nd(L) do write(" ", X) end foreach, write(" >>\n") end foreach.
LL is supposed to be a list of lists. The outer foreach-loop iterates L through this list, so each L is a list. The inner foreach-loop iterates X through the elements of L.
There are a number of things to notice:
- There is no comma before the keywords "do" and "end foreach".
- The Body of a foreach-term is a cut scope, so a cut meet in the body will not influence the iteration.
- A foreach-term always succeeds (or raises an exception), and no extra variables are bound after the evaluation of a foreach-term. Therefore, a foreach-term can only be used for its side effects.
clauses p(L) :- foreach X = list::getMember_nd(L) do stdio::write(X, "\n") end foreach, stdio::write("Finished\n").
Foreach can be used instead of traditional "fail-loops":
clauses p(L) :- X = list::getMember_nd(L), stdio::write(X, "\n"), fail. p(_L) :- stdio::write("Finished\n").
In this context it is advantageous that Body must be a procedure, because in a "fail-loop" the body may accidentally fail before reaching the fail in the loop. Another advantage is that a foreach loop succeeds when the loop is finished, whereas a fail loop fails, so that execution can continue in the same clause. Also notice that foreach can be properly nested:
clauses p(LL) :- foreach L = list::getMember_nd(LL) do foreach X = list::getMember_nd(L) do stdio::write(X, "\n") end foreach, stdio::write("Finished a list\n") end foreach, stdio::write("Finished all lists\n").