MadPhysicist
MadPhysicist

Reputation: 5831

Evaluating a List of Variables to a List of Their Values in Common Lisp

I am wondering how one can achieve the following. Suppose I have a list of variables that are bound by some let above. I would like to turn this list into a list of the values to which those variables are bound.

That is, suppose we have

(define make-plist-from-variables (variables)
  (let ((keys variables)
        (values (mapcar #'identity variables)))
    (if (eq (length keys) (length values))
     (make-plist keys values)
     nil))))

What can I use in place of #'identity to unpack those values properly?

At the moment, the following call produces the following output.

CL-USER> (let ((a 2) (b 3)) (make-plist-from-variables '(a b)))
(A A B B)

I would like it to be (A 2 B 3)

Upvotes: 2

Views: 354

Answers (2)

Sylwester
Sylwester

Reputation: 48745

It needs to be a macro because there is no way to fetch a variable's lexical value based on its symbol.

(defmacro make-plist-from-variables (&rest variables)
  (loop :for binding :in variables
        :collect `',binding :into result
        :collect binding :into result
        :finally (return `(list ,@result))))

(macroexpand-1 '(make-plist-from-variables a b))
; ==> (list 'a a 'b b) 

(let ((a 2) (b 3)) 
  (make-plist-from-variables a b))
; ==> (a 2 b 3)

EDIT

Implementation without loop using mapcan:

(defmacro make-plist-from-variables (&rest variables)
  `(list ,@(mapcan (lambda (v) `(',v ,v)) variables))

Upvotes: 5

coredump
coredump

Reputation: 38789

Functions don't have access to the lexical environment of their callers. More precisely, during evaluation you cannot access the values of lexical variables knowing only their symbols. Only macros have access to environment objects.

Special variables

You can use dynamic binding:

(defun foo ()
  (declare (special a))
  (symbol-value 'a))

(let ((a 3))
  (declare (special a))
  (foo))

=> 3

In your case, you would collect the symbol along its value, by using SYMBOL-vaLUE on all your symbols.

Related to your question is how to dynamically bind variables to values where the variable names and/or values are known at evaluation time; see special operator PROGV.

Macros

You could obtain e.g. an association list by writing the following code:

(acons 'a a (acons 'b b nil))

Depending on the use case behind your question, you may want to have a macro that expands into such code, that references the variables you want to evaluate.

Upvotes: 2

Related Questions