如标题所述,我尝试解决以下问题:
(setq s ())
(defun reassign (val)
(setq val 10))
(reassign s)
(print s)
-> Output: s = nil
我希望reassign
破坏性地分配s = 10
。
有没有一种简单的方法来处理这个问题,而不使用函数&中的变量名s
。只改变功能? (可能包括宏吗?)我将不胜感激任何建议! :)
答案 0 :(得分:2)
(defun reassign (val)
(setq val 10))
(reassign s)
当您致电(reassign s)
时,s
的值会传递到reassign
,并在val
本地绑定到nil
。在您的情况下,这将是s
,假设您已将()
与DEFVAR
一起声明,然后再将其设置为reassign
(请参阅setq and defvar in Lisp)。
在(setf (symbol-value 's) 10)
内,对SETQ
的调用会更改本地绑定。
每个符号都可以包含全局值。
如果要更改符号的值单元格,请使用SYMBOL-VALUE
访问者:
s
注意s
是如何引用的。您没有更改当前绑定到nil
的符号(s
,一个常量变量),但(SETF SYMBOL)
符号本身。 (defmacro reassign (place)
`(setf ,place 10))
就像直接致电SET
。
但是,如果要修改任何类型的 place ,特别是词法和动态变量绑定,则需要定义一个宏:
(gethash key table)
SETF
扩展为更新地点所需的代码。你也可以给reassign
而不只是一个不带引号的变量,然后更新表的内容。
对于局部变量,调用 {{1}}的代码最终会扩展为对特殊运算符SETQ
的调用,该运算符知道如何更改词法绑定(它还处理SYMBOL-MACROLET
绑定)。
答案 1 :(得分:1)
是的,你猜错了。你需要一个宏。
(defmacro reassign (var &optional (val 10)) `(setq ,var ,val))
(defvar s ()) ;; @Svante remarked that setq can be dangerous to create a variable
s ;; NIL
(reassign s)
s ;; 10
;; the `&optional (val 10)` makes the value optional and 10 to the
;; default value of val if not given.
在你的例子中
(defun reassign (val) (setq val 10))
val
是setq
特殊形式的第一个参数:val
中的setq
未成为s
,尽管您已经reassign
{ {1}} val
。它保持val
,以便您将功能范围中的10分配给val
。你可以通过以下方式看到它:
(setq s ())
(defun reassign (val)
(print "You gave for `val`:")
(print val)
(setq val 10)
(print "The form assigned 10 literally to val")
(print "Proof: Print out val in this scope:")
(print val))
(reassign s)
;;
;; "You gave for `val`:"
;; NIL
;; "The form assigned 10 literally to val"
;; "Proof: Print out val in this scope:"
;; 10
;; 10
(print val)
*** - SYSTEM::READ-EVAL-PRINT: variable VAL has no value
The following restarts are available:
USE-VALUE :R1 Input a value to be used instead of VAL.
STORE-VALUE :R2 Input a new value for VAL.
ABORT :R3 Abort main loop
;; since val has not been initiated before
此外,函数的setq
在功能范围内执行。这就是为什么在函数val之外保留旧值。
(defvar val ()) ;; NIL
(print val) ;; NIL
(defun reassign (val)
(print "You gave for `val`:")
(print val)
(setq val 10)
(print "The form assigned 10 literally to val")
(print "Proof: Print out val in this scope:")
(print val))
(reassign 'whatever) ;; inside function val becomes 10
;;
;;"You gave for `val`:"
;;WHATEVER
;;"The form assigned 10 literally to val"
;;"Proof: Print out val in this scope:"
;;10 ;; val becomes indeed 10 until leaving function
;;10
;; but retains old value after leaving the function
(print val)
;;
;; NIL
;; NIL
相反,宏以(reassign s)
形式替换宏调用(setq s 10)
。因此,在执行时,重新分配发生在我们定义(defvar s ())
的环境中。
因此,在重新分配后,s
会保留新分配的值,因为它已在工作环境中重新分配。