我有两个函数有一段重复代码,我想把这段代码抽象出来。
这段代码的作用是解析变量package
,得到两个函数变量package-symbo
和reciepe
。
一般来说都是写一个函数,package
进去,package-symbo
和reciepe
出来。
不过我还想到一个用macro的方法,大概是这样:
(defmacro with-recipe (&rest body)
`(let ((package-symbol (something using package))
(recipe (something using package)))
,@body))
这个方法看起来就很违规很危险,但是我不太明白具体为什么。我能想到的是用到的变量没有显式的表现出来(当然我在文档里都写清楚了)。是这样吗?
这样用没啥问题啊, macro 的作用就是去掉重复代码和嵌套函数
吹毛求疵一点就是没用 gensym 其它没啥问题,不过 Emacs 也没像样的 gensym 可以用。
gensym不是避免body內变量撞车用的么?(我没理解错的话)但是我的目的就是让body里的代码可以用package-symbol
和reciepe
啊。还是说是别的地方?
抱歉我打错了……已经在问题里修正
我问的就是这个地方,把package加进arglist里在下面就要各种quote,很麻烦而且容易错,我这样的话body里面和(something using package)
用package
就很方便。但是我不清楚这么做会不会出什么问题。
cireu
7
内置的gensym
和make-symbol
不能用吗?感觉还行啊
cireu
9
LdBeth
10
(make-symbol "f") ;; f
;; CL
(make-symbol "F") ;; #:F
区别多了去了,比如如果要打印出来再读回去,Elisp 完全不会区分 interned 和 uninternd
cireu
11
今天发现可以让emacs在打印的时候对gensym额外处理的
ELISP> (let ((print-gensym t))
(prin1-to-string `(let ((m ,(make-symbol "m"))))))
"(let ((m #:m)))"
ELISP> (let ((print-gensym nil))
(prin1-to-string `(let ((m ,(make-symbol "m"))))))
"(let ((m m)))"
gensym不是serializable的,按额外的格式打印出来然后read回去,每个gensym literal都会重新分配一个新的gensym,这意味着生成的sexp里所有gensym都不一样,所以并没有什么卵用
LdBeth
12
(eq #1='#:foo #1#) ;; always t
(setq print-gensym t
print-circle t)
(let ((s (gensym)))
(print (list s s)))
;; (#1=#:g7 #1#)
2 个赞