cireu
2019 年9 月 13 日 11:52
1
大多数人第一眼见到setf
,可能会简单的把f理解成form。这种解释很符合直觉,因为我们已经有了对symbol进行赋值操作的setq
。而setf
可以对form(广义变量)进行赋值。
然而这个直觉是错误的。 Deutsch在他的论文《A Lisp machine with very compact programs》中(原文 )提到
A more useful function is (SETFQ (fn arg1 ... argn) newvalue)
which quotes the function name and evaluates everything else.
This allows RPLACA, for example, to be defined as (LAMBDA (X Y) (SETFQ (CAR X) Y) ).
这里面提到的rplaca
在Elisp里叫做setcar
所以setf
是setfq
的缩写,f的意思是function。 另外在这篇论文中我们也可以看到MicroLisp引入了现在我们使用的广义变量的概念
参考:https://g000001.cddddr.org/3715857294
6 个赞
这里面的 setfq
底层是个正儿八经的 function,通过 cdr coding 直接修改 reference ,而不是像后来的 setf
用 macro expand 实现的。一来是因为 BBN LISP 那会还只有 FEXPR 没有 macro,二来 cdr coding 不是 portable 的,对实现要求限制比较大
3 个赞
cireu
2019 年9 月 15 日 02:09
6
不知道,顺带一提事实上Emacs里的cl-letf
在CL并没有对应的letf
存在,是Emacs自己加的扩展
cireu
2019 年9 月 15 日 02:12
7
(setf FORM VALUE)
可以理解成“使FORM eval的结果为VALUE”
Elisp里还有这种黑魔法
ELISP> (macroexpand-all '(setf (eq a 3) t))
(cond
(t
(setq a 3))
((eq a 3)
(setq a
(not 3))))
setf只用过一次, 发现修改了原list的元素, 会影响到其他变量, 所以setf之前先拷贝一下
cireu
2019 年9 月 15 日 04:16
9
本来就是不纯的操作,和其他语言修改struct的slot一样,struct的引用不变,内容变了。不过elisp有很多纯的列表操作,让你产生了错觉罢了
(defun replace-at (idx elem list)
(let ((tail (nthcdr (1+ idx) list))
head)
(dotimes (i idx)
(push (pop list) head))
(nconc (nreverse head) (cons elem tail))))
写一个纯的替换列表元素