Lisp-rookie here.
My goal is to define a macro that will make the keys of a dotted alist available as variables to access the corresponding values, hence the name »let-dotted-alist«. So what I want is:
(setq foo '((a . "aa") (b . "bb")))
(let-dotted-alist foo
(message (concat a b)))
==> "aabb"
Here's the best I could come up with so far:
(defmacro let-dotted-alist (alist &rest body)
"binds the car of each element of dotted ALIST to the corresponding cdr and makes them available as variables in BODY."
`(let ,(nreverse
(mapcar
(lambda (p) (list (car p) (cdr p)))
(eval alist)))
,@body))
The problem here is the eval
. I need it in order to be able to pass the alist as a variable (foo
) rather than a literal, which is the main use case when defining functions. For the macro to work out the code this variable needs to be bound already. Still everywhere I read that the use of eval tends to indicate a flaw in the code? Is there a way around it?
This would be a somewhat academic problem if Emacs 24 hadn't introduced eager macro expansion which wants to expand the macro at load time, when the variable (dotlist
in the following example) that should provide the alist is still void:
(defun concat-my-cdrs (dotlist)
(let-dotted-alist dotlist
(print (concat a b))))
Depending on how I evaluate this I either get »mapcar: Symbol's value as variable is void: dotlist« or »Eager macro-expansion failure: (void-variable dotlist)«. This makes sense of course, because the variable dotlist is indeed void at load time.
Now before I try to find a workaround along the lines of (locally) disabling eager macro expansion, is there any way to improve on the macro definition to avoid the eval
altogether?