[I wrote this mostly before coredump's answer was posted and then forgot about it. I think that answer is probably the one you want but perhaps this is worth reading as well.]
You can't retrieve the values of lexically-bound variables from their names. However, you can (as I think you are trying to do) write macros which bind variables and then remember the names of the bindings. Here are two, both of which introduce a local function called valof
which lets you get at the value of a binding by name. Neither are completely correct: see the end for why.
For both of these macros the trick is to maintain a secret association list between names and values.
(defmacro let/names (bindings &body forms)
(let ((<map> (make-symbol "MAP")))
`(let ,bindings
(let ((,<map> (list ,@(mapcar (lambda (b)
(etypecase b
(symbol
`(cons ',b ,b))
(cons
`(cons ',(car b) ,(car b)))))
bindings))))
(flet ((valof (s)
(let ((m (assoc s ,<map>)))
(if m
(values (cdr m) t)
(values nil nil)))))
,@forms)))))
Here is what the expansion of this looks like (here *print-circle*
is true so you can see that the gensymed name is used):
(let/names ((a 1))
(valof 'a))
-> (let ((a 1))
(let ((#1=#:map (list (cons 'a a))))
(flet ((valof (s)
(let ((m (assoc s #1#)))
(if m (values (cdr m) t) (values nil nil)))))
(valof 'a))))
Now, for instance:
> (let/names ((a 1))
(valof 'a))
1
t
> (let/names ((a 1))
(valof 'b))
nil
nil
But this macro is not actually really correct:
> (let/names ((a 1))
(setf a 2)
(valof 'a))
1
t
To deal with this problem the trick is to build a bunch of little functions which access the values of bindings. While doing that we can also allow assignment: mutation of the bindings.
(defmacro let/names (bindings &body forms)
(let ((<map> (make-symbol "MAP")))
`(let ,bindings
(let ((,<map> (list ,@(mapcar (lambda (b)
(etypecase b
(symbol
`(cons ',b
(lambda (&optional (v nil vp))
(if vp
(setf ,b v)
,b))))
(cons
`(cons ',(car b)
(lambda (&optional (v nil vp))
(if vp
(setf ,(car b) v)
,(car b)))))))
bindings))))
(flet ((valof (s)
(let ((m (assoc s ,<map>)))
(if m
(values (funcall (cdr m)) t)
(values nil nil))))
((setf valof) (n s)
(let ((m (assoc s ,<map>)))
(unless m
(error "~S unbound" s))
(funcall (cdr m) n))))
,@forms)))))
Here, again, is what the expansion looks like (much more complicated now):
(let/names ((a 1))
(valof 'a))
-> (let ((a 1))
(let ((#1=#:map
(list (cons 'a
(lambda (&optional (v nil vp))
(if vp (setf a v) a))))))
(flet ((valof (s)
(let ((m (assoc s #1#)))
(if m (values (funcall (cdr m)) t) (values nil nil))))
((setf valof) (n s)
(let ((m (assoc s #1#)))
(unless m (error "~S unbound" s))
(funcall (cdr m) n))))
(valof 'a))))
Now everything is better:
> (let/names ((a 1))
(valof 'a))
1
t
> (let/names ((a 1))
(valof 'b))
nil
nil
> (let/names ((a 1))
(setf a 2)
(valof 'a))
2
t
> (let/names ((a 1))
(setf (valof 'a) 3)
a)
3
Why neither of these macros is completely right. Neither macro deals with declarations properly: in a case like
(let/names ((a 1))
(declare (type fixnum a))
...)
The declaration will end up in the wrong place. Dealing with this requires 'lifting' declarations to the right place, which is easy to do but I'm not going to make these even more complicated than they already are.