cl-lc
2024-10-12
List comprehensions
CL-LC provides list comprehensions (and other “comprehensions”, like dictionary comprehensions) using the technique presented in Mario Latendresse, “Simple and Efficient Compilation of List Comprehensions in Common Lisp.”
CL-LC comprehensions expand into Iterate rather than loop
. One
way to think of CL-LC is as an alternative front-end syntax for
Iterate preserving Iterate’s extensibility.
Syntax
A list comprehension consists of an expression, whose results will be collected into a list, followed by a list of filters and generators.
Generators are expressions that start with iterate:for
.
(list-of x (for x in xs))
≡ (mapcar #'identity xs)
The binding of a generator can use destructuring:
(list-of key (for (key . value) in alist))
Generators can be made parallel simply by enclosing them in a list.
(list-of (list x y)
((for x in xs)
(for y in ys)))
≡ (list-of (list x y)
(for (x y) in (mapcar #'list xs ys)))
Filters are ordinary expressions that filter the results of each generator:
(list-of x (for x in (iota 10)) (evenp x))
=> (2 4 6 8 10)
You may use if
, when
, and unless
as syntactic sugar:
(list-of x (for x in (iota 10)) if (evenp x))
=> (2 4 6 8 10)
(list-of x (for x in (iota 10)) unless (evenp x))
=> (1 3 5 7 9)
Generators can be any for
clause understood by Iterate, including
user-defined ones. We also provide an additional driver, (for .. over ...)
, which allow iterating over any sequence.
Other macros
count-of
≡ (count-if #'identity (list-of ...))
any-of
≡ (some #'identity (list-of ...))
all-of
≡ (every #'identity (list-of ...))
none-of
≡ (notany #'identity (list-of ...))
sum-of
≡ (reduce #'+ (list-of ...))
product-of
≡ (reduce #'* (list-of ...))
max-of
≡ (reduce #'max (list-of ...))
min-of
≡ (reduce #min (list-of ...))
do-for
do-for
is a cross between a list comprehension and do
. It does no
accumulating or reducing; it just binds variables.
(let ((pairs '()))
(do-for ((for x in '(a b c))
(for y in '(1 2 3))
(<= y 2))
(push (cons x y) pairs))
(nreverse pairs))
=> ‘((A . 1) (A . 2) (B . 1) (B . 2) (C . 1) (C . 2))
dict-of
Using dict-of
construct an equal
hash table from pairs of (multiple) values.
(hash-table-alist (dict-of (values k v) (for (k . v) in '((a . 1) (b . 2))))) => '((b . 2) (a . 1))