我不知道这里发生了什么,文中的宏观例子.基本上,不熟悉如何使用get-setf-method,内置宏(可能是函数?).具体来说,get-setf-method的某些返回值为零的情况怎么样?例如(get-setf-method'x)
NIL ;
NIL ;
(#:NEW-3069) ;
(SETQ X #:NEW-3069) ;
X
Run Code Online (Sandbox Code Playgroud)
为什么这个示例代码首先将第五个返回值设置为第二个返回值,以进行初始化?最后它如何处理在表达式中设置变量的顺序,例如(aref ar(incf i)
(get-setf-method '(aref ar (incf i)))
(#:G3070 #:G3071) ;
(AR (INCF I)) ;
(#:G3072) ;
(SYSTEM::STORE #:G3070 #:G3071 #:G3072) ;
(AREF #:G3070 #:G3071)
Run Code Online (Sandbox Code Playgroud)
这是宏的定义:
(defmacro sortf (op &rest places)
(let* ((meths (mapcar #'(lambda (p)
(multiple-value-list
(get-setf-method p)))
places))
(temps (apply #'append (mapcar #'third meths))))
`(let* ,(mapcar #'list
(mapcan #'(lambda (m)
(append (first m)
(third m)))
meths)
(mapcan #'(lambda (m)
(append (second m)
(list (fifth m))))
meths))
,@(mapcon #'(lambda (rest)
(mapcar
#'(lambda (arg)
`(unless (,op ,(car rest) ,arg)
(rotatef ,(car rest) ,arg)))
(cdr rest)))
temps)
,@(mapcar #'fourth meths))))
Run Code Online (Sandbox Code Playgroud)
这实际上是一些旧的代码. get-setf-method实际上被问题SETF-METHOD-VS-SETF-METHOD Writeup中get-setf-expansion描述的替换.那么你最近应该感兴趣的是.它返回的值是您在某个位置安全存储值所需的代码段.这非常重要,因为错误地编写modyfing宏非常容易.get-setf-expansion
至于为什么有些值可以nil,文档中的一个示例get-setf-expansion实际上显示了一些值如何nil:
(get-setf-expansion 'x)
;=> NIL, NIL, (#:G0001), (SETQ X #:G0001), X
Run Code Online (Sandbox Code Playgroud)
但这些价值观是什么?为此,我们需要查看文档的语法:
句法:
get-setf-expansion place
&optionalenvironment⇒ 瓦尔,丘壑,商店瓦尔,作家的形式,读者形式
论点和价值观:
放置一个地方.
环境 - 环境对象.
vars,vals,store-vars,writer-form,reader-form-setf expansion.
这五个返回值在5.1.1.2 Setf Expansions中描述:
临时变量列表一个符号列表,命名临时变量按顺序绑定,就像let*一样,绑定到值表单生成的值.
值列表形成表单列表(通常是地点的子表单),其在评估时产生相应临时变量应绑定到的值.
存储变量列表一个符号列表,用于命名临时存储变量,这些变量用于保存将分配给该位置的新值.
存储形式 可以引用临时变量和存储变量,并更改地点的值,并保证返回存储变量的值作为其值,这是setf要返回的正确值.
访问表单可以引用临时变量,并返回该地点的值.
那么这个例子中的值是什么意思呢?
(get-setf-expansion 'x)
;? NIL, NIL, (#:G0001), (SETQ X #:G0001), X
Run Code Online (Sandbox Code Playgroud)
要写入变量x,我们不需要任何临时存储,并且由于没有临时值,我们不需要任何表单来为它们生成值.我们在这里可以注意到,第一个和第二个值总是列表,它们应该始终具有相同的长度.第三个值是商店变量列表.这是一个列表,因为我们实际上可以setf用来修改多个值,但在这种情况下只有一个.这里的变量是宏应该实际存储场所新值的位置.然后,它就是作家形式 (setq x #:g0001),它实际上会把价值放在这个地方. x当然,这是一种阅读价值的简单方法.
作为一个更复杂的例子,请看一下SBCL的这个成绩单:
CL-USER> (defstruct person
person-name)
;? PERSON
CL-USER> (get-setf-expansion '(char (person-name (first (second list-of-list-of-persons))) 3))
; (#:TMP965)
; ((PERSON-NAME (FIRST (SECOND LIST-OF-LIST-OF-PERSONS))))
; (#:NEW964)
; (SB-KERNEL:%CHARSET #:TMP965 3 #:NEW964)
; (CHAR #:TMP965 3)
Run Code Online (Sandbox Code Playgroud)
这意味着如果我们想要更改人员列表中第二个人名单中第一个人姓名的第四个字符,我们可以这样做:
(let* ((temp965 (person-name (first (second list-of-list-of-persons))))
(old-char (char tmp965 3))) ; optional
(setq new964 <compute-new-value>)
(sb-kernel:%charset tmp965 3 new964))
Run Code Online (Sandbox Code Playgroud)
我们可以根据需要计算新值(只需填写<compute-new-value>),如果需要,我们甚至可以引用旧值(通过包含可选行).我们需要做的只是设置new964为新值,然后执行给我们的writer-form.
get-setf-expansion有关Stack Overflow的更多示例: