如何在lisp中全局更改函数中的变量值
我想知道是否有任何方法可以用LISP中的指针模拟C的行为。在C语言中,如果更改指针指向的变量的值,则该变量具有全局效应(即,该值也将在函数外部更改) 所以如果我有如何在lisp中全局更改函数中的变量值,lisp,common-lisp,argument-passing,Lisp,Common Lisp,Argument Passing,我想知道是否有任何方法可以用LISP中的指针模拟C的行为。在C语言中,如果更改指针指向的变量的值,则该变量具有全局效应(即,该值也将在函数外部更改) 所以如果我有 (defun mutate ( a ) (some-magic-function a 5) ) a在调用mutate后会变为5,不管它之前是什么 我知道有列表的元素是可能的(很大程度上是一种副作用) 但我想知道如何为整个列表执行此操作。使用函数 如果要使用函数,必须传递符号本身: (defun mutate (symbol
(defun mutate ( a )
(some-magic-function a 5)
)
a在调用mutate后会变为5,不管它之前是什么
我知道有列表的元素是可能的(很大程度上是一种副作用)
但我想知道如何为整个列表执行此操作。使用函数
如果要使用函数,必须传递符号本身:
(defun mutate (symbol value)
(setf (symbol-value symbol) value))
(mutate 'foo 42)
foo
==> 42
请注意,mutate
的symbol
参数被引用
使用宏
符号
参数不再需要引用
讨论
参数在Lisp中,这意味着函数看到的是其参数的值,而不是其存储位置。
因此,作为(foo(!5))
,(foo 120)
,(foo x)
调用的函数只看到数字120
,完全无法知道该数字是由函数返回的(第一种情况)、是文字(第二种情况)还是存储在变量中(第三种情况)
宏接收它们转换的代码并将新代码传递给编译器(或解释器)。因此,宏可以决定如何修改它们的参数(在这种情况下调用)。C代码讨论
解决问题的要点,但看起来确实有一点混淆,即您正在模拟的C代码中发生了什么:
我想知道是否有任何方法可以模仿C语言的行为
LISP中的指针。在C语言中,如果你改变一个变量的值
指针指向,它具有全局效果(即该值将为
在功能之外也发生了更改)
考虑以下内容,我认为这与您提供的Lisp代码最为相似:
#包括
INTA=3;
int变异(int a){
返回a=5;
}
int main(){
改变(a);/*或改变(8)或任何其他论点*/
printf(“%d\n”,a);/*打印3*/
返回0;
}
代码打印三个,因为mutate
中的a
是一个仅存在于mutate
中的变量。仅仅因为它与全局a
共享一个名称并不意味着更改一个将更改另一个。此代码中唯一可以更改mutate
变量a
值的位置是mutate
。您没有“更改[a]指针指向的变量的[a]值”选项。您可以做的是将指针传递给变量的值,通过该指针修改值,然后观察值中的结果。这将对应于此C代码:
#包括
INTA=3;
int突变(int*a){
返回(*a=5);
}
int main(){
突变&a;
printf(“%d\n”,a);/*打印5*/
返回0;
}
通过结构间接寻址
您也可以在CommonLisp中使用您喜欢的任何间接方式来执行类似的操作。例如,如果将a
acons
单元格设置为car
为3
,则可以传递该cons
并修改其car
的值:
CL-USER>(定义参数*a*(cons 3 nil))
*A*
CL-USER>(解除突变(cons)
(环境运输及工务局局长(车辆管制)5)
变异
CL-USER>(变异*a*)
5.
CL-USER>(汽车*a*)
5.
但是,在Lisp中没有运算符的地址,因此无法完全模拟C代码,如果要使用这种方法,则始终需要以某种方式“包装”该值。您可以使用公共Lisp中的现有结构,如cons单元格、向量或任何其他可以找到的内容
广义参考文献
尽管Common Lisp没有C风格的指针,但它定义了一种非常广泛的方法来引用用于读写的内存位置,称为
广义引用是一种形式的使用,有时称为
放置,就好像它是一个可以读写的变量。这个
place的值是place表单计算到的对象。这个
可以使用setf更改位置的值。绑定的概念
在Common Lisp中没有定义位置,但可以定义实现
允许通过定义此概念来扩展语言
在Common Lisp中,可以使用setf
指定位置。您可以使用全局变量符号作为setf
的位置,或使用symbol value
修改全局变量值的共同点。也就是说,在诸如(defparameter*a*3)
之类的定义之后,*a*
和(符号值'*a*)
都是可以为*a*
存储新值的位置。因此,我宁愿用变量名place
和value
编写一个宏,这样就可以清楚地看到,任何位置都可以用作参数:
(defmacro mutate(位置值)
`(setf、地点、价值)
使用词汇闭包模拟指向变量的C风格指针
因为词汇变量也是位置,所以还有另一个选项尚未考虑。您可以使用词法闭包来创建函数,这些函数将为您提供与C风格指针相同的功能
(定义宏生成指针(位置)
`(λ(op和可选值)
(电子计算机操作)
((读),地点)
((写入)(setf,放置值щщ))
(让*((x 3)
(xp(生成指针x)))
(funcall xp'write 5);将新值写入x
(列表(funcall xp'读取);从x到xp读取值
x) );直接从x读取值
;=> (5 5)
在这段代码中,makepointer
返回一个可以用一个或两个参数调用的函数。第一个参数应该是符号,read
或
(defmacro mutate (symbol value)
`(setf ,symbol ,value))
(mutate foo 42)
foo
==> 42
(make-pointer (aref some-array (print 2)))
;;; The basic idea is to use closures
;;; It looks as though we are done
;;; now we can translate C code
;;; &x = (addr x), *x = (data x)
;;; The trouble is, we have a multiple evaluation bug.
(defun mutate-to-five (ptr) | void mutate_to_five(int *a)
(setf (deref ptr) 5)) | { *ptr = 5; }
|
(defparameter a 42) | int a = 42;
| /*...*/
(mutate-to-five (ref a)) | mutate_to_five(&a);
;;;
;;; Lisp references: pointer-like place locators that can be passed around.
;;; Source: http://www.kylheku.com/cgit/lisp-snippets/plain/refs.lisp
;;;
;;; How to use:
;;;
;;; Produce a reference which "lifts" the place designated
;;; by form P:
;;;
;;; (ref p)
;;;
;;; Dereference a reference R to designate the original place:
;;;
;;; (deref r)
;;; (setf (deref r) 42) ;; store new value 42
;;;
;;; Shorthand notation instead of writing a lot of (deref)
;;; Over FORMS, A is a symbol macro which expands to
;;; (DEREF RA), B expands to (DEREF RB):
;;;
;;; (with-refs ((a ra) (b rb) ...)
;;;
;;; ... forms)
;;;
(defstruct ref
(get-func)
(set-func))
(defun deref (ref)
(funcall (ref-get-func ref)))
(defun (setf deref) (val ref)
(funcall (ref-set-func ref) val))
(defmacro ref (place-expression &environment env)
(multiple-value-bind (temp-syms val-forms
store-vars store-form access-form)
(get-setf-expansion place-expression env)
(when (cdr store-vars)
(error "REF: cannot take ref of multiple-value place"))
`(multiple-value-bind (,@temp-syms) (values ,@val-forms)
(make-ref
:get-func (lambda () ,access-form)
:set-func (lambda (,@store-vars) ,store-form)))))
(defmacro with-refs ((&rest ref-specs) &body forms)
`(symbol-macrolet
,(loop for (var ref) in ref-specs
collecting (list var `(deref ,ref)))
,@forms))