Iterate provides defmacro-clause to make it easy to write new clauses. Here’s a simple one that builds up an FSet set:

(defmacro-clause (collecting-set x &optional into var) `(reducing ,x by #'with into ,var initial-value (empty-set)))

But the syntax of defmacro-clause is not as flexible as I would like. In particular, there is no way to supply more than one expression. To collect an FSet map, I would like to be able to write:

(collecting-map k v into result)

But the syntax of defmacro-clause won’t allow that.

However, there is still hope. Iterate uses a code walker that expands macros. All we have to do to get both the benefits of defmacro-clause (the ability to collect to a particular variable) and the syntax we want is to write two macros: a macro with the syntax that we want, which expands into an auxiliary Iterate macro.

(defmacro-clause (collecting-map-aux kv &optional into var) `(reducing ,kv by (lambda (map kv) (with map (car kv) (cdr kv))) ,var initial-value (empty-map))) (defmacro collecting-map (k v &rest args) `(collecting-map-aux (cons ,k ,v) ,@args))

And then we can write: