Many have suggested adding a lambda reader construct to Emacs Lisp: something like #(princ $1)
, which would be translated to (lambda (x) (princ x))
.
Well, it turns out that you can (ab)use the existing reader constructs for this purpose. Specifically, ,x
and ,@x
are translated to (\, x)
and (\,@ x)
, which are without meaning outside of a backquoted list.
That means that it is legal to define and use \,
as a function or macro:
(defmacro \, (body) "Return an anonymous function. In BODY, symbols of the type $N, where N is a non-zero, positive number, represent positional arguments. $* represents a list of optional remaining arguments. ,(+ $1 $2) expands to (lambda ($1 $2) (+ $1 $2)). See `lambda'." (let ((total 0) rest) (cl-labels ((search (form) (if (consp form) (progn (search (car form)) (search (cdr form))) (if (eq form '$*) (setq rest t) (let ((s (prin1-to-string form))) (if (string-match "^\\$\\([1-9][0-9]*\\)$" s) (let ((n (string-to-number (match-string 1 s)))) (setq total (max total n))))))))) (search body)) `(lambda ,(append (cl-loop for n from 1 upto total collect (intern (format "$%d" n))) (and rest '(&rest $*))) ,body)))
With this macro, you can replace
(mapcar (lambda (x) (with-output-to-string (princ x))) objects)
with
(mapcar ,(with-output-to-string (princ $1)) objects)
If you want your lambda to accept an unlimited number of arguments, use `$*':
(advice-add 'some-function :before ,(dolist (x $*) (message "%s" x)))
What are the downsides? Strictly, there is only one. The docstring for the macro above will not be displayed in Emacs' help system, which will always display the built-in information about ,
.