如何 apply 一个宏?


#1

或者,如何 unpack 一个 list?

如下所示,如果 sum 是一个函数,则通过 apply 传递一个 list 作为参数;但如果 sum 是一个宏,就不适用了:

(defun sum (a b c)
  (+ a b c))

(apply 'sum '(1 2 3)) ;; => 6

(defmacro sum (a b c)
  `(+ ,a ,b ,c))

(apply 'sum '(1 2 3)) ;; => Invalid function: sum


#2

applyfuncall 不能用在宏上面。不知道你的原始问题是什么,unpack 用 ,@ 就行。就这个例子的话:

(defmacro sum (list)
  `(+ ,@list)
(sum (1 2 3)) ; => 6

#3
  • apply 应该打上引号 :sweat_smile:

  • 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)))
    

#4

好像还是没回答“如何apply一个宏”这个问题。我现在有同样的需求:把SPCM-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))

#5
(defmacro jester/with-leader (&rest args)
   `(progn
      (leader-def ,@args)
      (eader-emacs-def ,@args)))

#6

解决了。之前报过一些错让我以为宏展开后的结果里不能有宏,还想怎么在defmacro里面eval这个宏再展开……


  (defmacro jester/with-leader (&rest args)
    `(leader-def ,@args)
    `(leader-emacs-def ,@args))

这样为什么不行?defmacro不是&rest BODY么?


#7
(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))

因為函數只返回最后一个表達式的结果


#8

我试着用了macrostep-expand,结果第一步把defun展开成(function (lambda) ...)了,后面看花眼没注意到重点,等下再看看macrostep究竟怎么用。