或者,如何 unpack 一个 list?
如下所示,如果 sum
是一个函数,则通过 apply
传递一个 list 作为参数;但如果 sum
是一个宏,就不适用了:
(defun sum (a b c) (+ a b c)) |
(defmacro sum (a b c) `(+ ,a ,b ,c)) |
或者,如何 unpack 一个 list?
如下所示,如果 sum
是一个函数,则通过 apply
传递一个 list 作为参数;但如果 sum
是一个宏,就不适用了:
(defun sum (a b c) (+ a b c)) |
(defmacro sum (a b c) `(+ ,a ,b ,c)) |
apply
和 funcall
不能用在宏上面。不知道你的原始问题是什么,unpack 用 ,@ 就行。就这个例子的话:
(defmacro sum (list)
`(+ ,@list)
(sum (1 2 3)) ; => 6
apply 应该打上引号
elisp 怎样迭代调用一系列相似的函数? 这个问题,我想用试试用宏展开它,递归的时候没脑袋没转过弯,backquote 其实就是 “apply” 的意思吧,然后也没想到 cdr
接着使用 @
:
(defmacro recall-rest (arg fn &rest fn-rest)
(if fn
`(funcall ',fn (recall-rest ,arg ,(car fn-rest) ,@(cdr fn-rest)))
`,arg))
(macroexpand-all '(recall-rest arg fun1 fun2 fun3))
;; =>
;; (funcall (quote fun1)
;; (funcall (quote fun2)
;; (funcall (quote fun3)
;; arg)))
好像还是没回答“如何apply一个宏”这个问题。我现在有同样的需求:把SPC
和M-m
作为evil-normal-state和evil-emacs-state下的leader key,用general可以生成两个宏,它们可以用来define key:
(general-create-definer leader-def :prefix "SPC" :states '(normal motion visual))
(general-create-definer leader-emacs-def :prefix "M-m" :states '(insert emacs))
它们的用法是:
(leader-def "b b" 'switch-to-buffer)
(leader-emacs-def "b b" 'switch-to-buffer)
我想把它们合并成一句:
(with-leader "b b" 'switch-to-buffer)
即
(defmacro jester/with-leader (&rest args)
`((apply 'leader-def args)
(apply 'leader-emacs-def args))
)
当然这里apply是不能用的,backquote的用法我可能也写错了,怎样写才对?
要用macroexpand
?但是我搜了一下spacemacs的代码,只有一处用到了它,大概长这样:
`(let (,@vars)
,@inits
(prog1
,(macroexpand `(mocker-flet (,@specs)
,@body))
,@verifs))
(defmacro jester/with-leader (&rest args)
`(progn
(leader-def ,@args)
(eader-emacs-def ,@args)))
解决了。之前报过一些错让我以为宏展开后的结果里不能有宏,还想怎么在defmacro里面eval这个宏再展开……
(defmacro jester/with-leader (&rest args)
`(leader-def ,@args)
`(leader-emacs-def ,@args))
这样为什么不行?defmacro
不是&rest BODY
么?
(defmacro jester/with-leader (&rest args)
`(leader-def ,@args)
`(leader-emacs-def ,@args))
(macroexpand-1 '(jester/with-leader "zz" bar))
;;=> (leader-emacs-def "zz" bar)
(defmacro jester/with-leaderz (&rest args)
`(progn (leader-def ,@args)
(leader-emacs-def ,@args)))
(macroexpand-1 '(jester/with-leaderz "zz" bar))
;; => (progn (leader-def "zz" bar) (leader-emacs-def "zz" bar))
因為函數只返回最后一个表達式的结果
我试着用了macrostep-expand
,结果第一步把defun
展开成(function (lambda) ...)
了,后面看花眼没注意到重点,等下再看看macrostep究竟怎么用。