Language Reference/Terms/Foreach

From wiki.visual-prolog.com

< Language Reference‎ | Terms

Revision as of 10:37, 12 February 2013 by Thomas Linder Puls (talk | contribs) (subarticle)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

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.

Example
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.
Example
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").