Common lisp 在Common Lisp中将变量列表计算为其值列表

Common lisp 在Common Lisp中将变量列表计算为其值列表,common-lisp,Common Lisp,我想知道怎样才能做到以下几点。假设我有一个变量列表,这些变量由上面的let绑定。我想把这个列表转换成一个值列表,这些变量被绑定到这些值上 也就是说,假设我们有 (define make-plist-from-variables (variables) (let ((keys variables) (values (mapcar #'identity variables))) (if (eq (length keys) (length values)) (ma

我想知道怎样才能做到以下几点。假设我有一个变量列表,这些变量由上面的
let
绑定。我想把这个列表转换成一个值列表,这些变量被绑定到这些值上

也就是说,假设我们有

(define make-plist-from-variables (variables)
  (let ((keys variables)
        (values (mapcar #'identity variables)))
    (if (eq (length keys) (length values))
     (make-plist keys values)
     nil))))
我可以用什么来代替
#“identity
来正确解压这些值

此时,下面的调用生成以下输出

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

我希望它是
(a2b3)

函数不能访问其调用者的词法环境。 更准确地说,在求值过程中,您不能只知道词法变量的符号就访问它们的值。只有宏才能访问

特殊变量 您可以使用动态绑定:

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

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

=> 3
在您的情况下,您可以通过在所有符号上使用来收集符号及其值

与您的问题相关的是,如何将变量动态绑定到在计算时已知变量名称和/或值的值;请看特别接线员

宏 您可以通过编写以下代码获得关联列表:

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

根据问题背后的用例,您可能希望有一个宏扩展成这样的代码,引用您要计算的变量。

它需要是一个宏,因为无法根据变量的符号获取变量的词法值

(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)
编辑

不使用
循环的实现
使用:


很好的代码,但是你应该解释为什么它必须是一个宏(这也在另一个答案中,但是你的答案本身应该是可以理解的)。@Barmar谢谢。刚刚做了:)看起来不错。是否可以不使用
循环
?@madpysicator在宏中,您只有表示代码的数据。不是价值观。该函数仅操作符号,并将其引用以获取符号,而不获取结果中的值。在宏中,
a
b
没有值,因为这发生在代码运行之前,可能是在编译文件时。如果你给它传递了一个错误的变量,它将毫无错误地展开,但是在运行时以后对结果的计算将失败。@MadPhysicator因此,由于我们在宏中,所以我们只有列表和符号。因此,变量名就是我们所拥有的全部。我们生成新的代码进行求值,因此
`(',v,v)
生成一个引用版本和一个裸版本,例如
('b)
,这样当在最终扩展中求值时,您可以得到名称,然后得到值。词汇变量在CL中没有可访问的表示。您不应该将数字与EQ进行比较。使用EQL或=。很好。谢谢
(defmacro make-plist-from-variables (&rest variables)
  `(list ,@(mapcan (lambda (v) `(',v ,v)) variables))