CL Enumerations: Macro FOREACH
 

Macro FOREACH

Package:

CL.EXTENSIONS.ENUMERATIONS

Syntax:

  foreach (var object &rest keys) &body forms-and-clauses
  => result
  

Arguments and Values:

var---a non evaluated symbol

object---an object instance

keys---a list of key-value pairs

forms-and-clauses---a list of forms and LOOP clauses

Description:

The FOREACH macro is a simplified iteration construct over an enumerable object. FOREACH is a thin macro over LOOP and it mixes, in a hybrid -- and maybe not so beautiful -- style the DOTIMES/DOLIST shape with LOOP clauses.

forms-and-clauses are executed in an environment where var is bound to the elements of the result of

  (apply #'enum:enumerate object keys)
  

If keys contains a non-NIL :reverse keyword, then the enumeration must be bi-directional and PREVIOUS and HAS-PREVIOUS-P will be used to traverse it. :reverse and its value will be still passed to the embedded call to ENUMERATE. This is obviously only useful only for enumerations that can start "in the middle".

forms-and-clauses can start with some declarations and then continue with either regular forms or LOOP clauses. After the first LOOP clause appears in FORMS-AND-CLAUSES, standard LOOP rules should be followed.

The result returned by FOREACH is whatever is returned by forms-and-clauses according to standard LOOP semantics.

Examples:

Here are some examples of FORACH.

  cl-prompt> (setf le (enumerate '(1 2 3)))
  #<CONS enumeration ...>

  cl-prompt> (foreach (i le) (print i))
  1
  2
  3
  NIL
  
Of course, FOREACH is smarter than that:
  cl-prompt> (foreach (i (vector 'a 's 'd))
                 (declare (type symbol i))
                 (print i))
  A
  S
  D
  NIL
  
Apart from declarations, FOREACH is just a macro built on top of LOOP, therefore you can leverage all the LOOP functionality.
  cl-prompt> (foreach (i (vector 1 2 3 4))
                 (declare (type fixnum i))
                 when (evenp i)
                   collect i)
  (2 4)
  
While this creates an admittedly strange hybrid between the standard DO... operators and LOOP, it does serve the purpose. The right thing would be to have a standardized way of extending LOOP. Alas, there is no such luxury.

Finally an example of a reverse enumeration:

  cl-prompt> (foreach (i (vector 1 2 3 4 5 6 7 8) :reverse t :start 4)
                 when (evenp i)
                   collect i)
  (4 2)
  

Affected By:

None.

Exceptional Situations:

None.

See Also:

ENUMERATION class, BOUNDED-ENUMERATION, NUMBER-ENUMERATION, BI-DIRECTIONAL-ENUMERATION, SEQUENCE-ENUMERATION, LIST-ENUMERATION, ARRAY-ENUMERATION, VECTOR-ENUMERATION, STRING-ENUMERATION, HASH-TABLE-ENUMERATION, NEXT, HAS-NEXT-P, CURRENT, PREVIOUS, HAS-PREVIOUS-P.

Notes:

None.