Next: , Previous: , Up: For   [Contents][Index]


1 Introduction

Despite the same name as the imperative iteration construct in Algol, this package is inspired by the iteration and sequence forms1 in Racket, which in turn is inspired by SRFI (Scheme Request for Implementation) 42. They are designed in such a way that they can be both efficient and generic. The distinctive feature of them is that a sequence form can act either as an expander or a generator (see (elisp)Generators), and the former is used in the iteration forms, that is, for-fold forms and derivatives. Essentially, for-fold forms are equivalent to named-let forms (see (elisp)Local Variables), whose self-tail calls are optimized to while loops (see (elisp)Iteration)2. Therefore, the iteration forms can act as Lispy3 and functional4 replacements of the built-in iteration forms, such as cl-loop (see (cl)Loop Facility).

A simple yet contrived cl-loop form:

(cl-loop for item in '(a 2 "3")
         for number = (or (and (numberp item)
                               item)
                          (and (stringp item)
                               (string-to-number item)))
         if number collect number)
     ⇒ (2 3)

An equivalent for-list form with an :if-let special clause:

(for-list ((item '(a 2 "3"))
           (:if-let
            (number (or (and (numberp item)
                             item)
                        (and (stringp item)
                             (string-to-number item)))))
           number))
     ⇒ (2 3)

An equivalent for-list form with a :pcase special clause:

(for-list ((item '(a 2 "3"))
           (:pcase item
                   (or (and (cl-type number)
                            number)
                       (and (cl-type string)
                            (app string-to-number number))))
           number))
     ⇒ (2 3)

All other iteration forms are derived from for-fold forms, which in turn are equivalent to named-let forms. In contrast, sequence forms are defined through the definer define-for-sequence. When sequence forms are used in iteration clauses, they support aliases, expanders, as well as dynamic dispatch; when used as function forms, their function definitions are invoked, which are the corresponding generators.

Aliases and expanders are available in iteration clauses:

(for-list ((item (in-producer #'random))
           (5)
           item))
     ⇒ #<a list of five pseudo-random integers>

Generators are available in function forms:

(cl-loop for item iter-by (for-in-producer #'random)
         repeat 5 collect item)
     ⇒ #<a list of five pseudo-random integers>

The iteration forms use pcase-let (see (elisp)Destructuring with pcase Patterns) as the binding construct where it makes sense. This is useful for, but not only for destructuring.

The destructuring capability of cl-loop forms:

(cl-loop for (number . string)
           in '((1 . "1") (2 . "b") (3 . "3"))
         if (eql number (string-to-number string))
           collect number)
     ⇒ (1 3)

for-list forms use pcase-let forms:

(for-list ((`(,number . ,string)
            '((1 . "1") (2 . "b") (3 . "3")))
           (:if (eql number (string-to-number string)))
           number))
     ⇒ (1 3)

All things considered, the iteration forms are both as efficient as specialized iterations and as generic as the sequence functions (see (elisp)Sequence Functions). Moreover, they are more easily extensible as compared to cl-loop forms.


Footnotes

(1)

Following Scheme as opposed to Common Lisp and Emacs Lisp (see (elisp)Forms), this manual refers to an arbitrary Lisp object (see (elisp)Lisp Data Types) as a form and a form intended to be evaluated (see (elisp)Evaluation) as an expression. This means expressions are a subset of forms. Similarly, what Common Lisp calls a subexpression is called a subform in this manual.

(2)

In fact, for-fold forms directly expand to while loops for efficiency. Moreover, the full recursive power of named-let forms are not needed for sequence iterations. Nonetheless, it is useful to think of for-fold forms in terms of the equivalent named-let forms.

(3)

Lispy in the sense that they use Lisp-like parenthesized syntax as opposed to Algol-like keyword-delimited syntax. The Common Lisp Loop Facility has its origin in Interlisp and has been criticized for its Algol-like syntax.

(4)

Functional in the sense that they are equivalent to applications of self-tail-recursive functions that transform local states.


Next: Basic Concepts, Previous: For, Up: For   [Contents][Index]