Next: Basic Concepts, Previous: For, Up: For [Contents][Index]
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.
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.
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.
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.
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]