Macros 如何避免defmacro中的eval?

Macros 如何避免defmacro中的eval?,macros,common-lisp,Macros,Common Lisp,我编写了一个宏,它接受要调用的lambda列表并生成一个函数。lambda始终在defun参数列表中计算,但不在defmacro中计算。如何避免在defmacro内部调用eval 此代码适用于: (defmacro defactor (name &rest fns) (let ((actors (gensym))) `(let (;(,actors ',fns) (,actors (loop for actor in ',fns

我编写了一个宏,它接受要调用的lambda列表并生成一个函数。lambda始终在
defun
参数列表中计算,但不在
defmacro
中计算。如何避免在
defmacro
内部调用
eval

此代码适用于:

(defmacro defactor (name &rest fns)
  (let ((actors (gensym)))
    `(let (;(,actors ',fns)
           (,actors (loop for actor in ',fns
                          collect (eval actor)))) ; This eval I want to avoid
       (mapcar #'(lambda (x) (format t "Actor (type ~a): [~a]~&" (type-of x) x)) ,actors)
       (defun ,name (in out &optional (pos 0))
         (assert (stringp in))
         (assert (streamp out))
         (assert (or (plusp pos) (zerop pos)))
         (loop for actor in ,actors
               when (funcall actor in out pos)
               return it)))))

;; Not-so-relevant use of defactor macros
(defactor invert-case
    #'(lambda (str out pos)
        (let ((ch (char str pos)))
          (when (upper-case-p ch)
            (format out "~a" (char-downcase ch))
            (1+ pos))))
  #'(lambda (str out pos)
      (let ((ch (char str pos)))
        (when (lower-case-p ch)
          (format out "~a" (char-upcase ch))
          (1+ pos)))))
此代码的计算结果与预期一致:

Actor (type FUNCTION): [#<FUNCTION (LAMBDA (STR OUT POS)) {100400221B}>]
Actor (type FUNCTION): [#<FUNCTION (LAMBDA (STR OUT POS)) {100400246B}>]
INVERT-CASE
其余的显然都不起作用

如果我将
defmacro
转换为
defun
,则不需要
eval

(defun defactor (name &rest fns)
  (defun name (in out &optional (pos 0))
    (assert (stringp in))
    (assert (streamp out))
    (assert (or (plusp pos) (zerop pos)))
    (loop for actor in fns
          when (funcall actor in out pos)
          return it)))
但是,它总是定义函数名,而不是传递的函数名参数(应该引用)


是否可以编写
defactor
,并且可以传递函数名,而不是
defun
版本,并且在
版本中不使用
eval

第一个
循环
会使事情变得更加复杂。。。只需收集参数即可

(defmacro defactor (name &rest fns)
  (let ((actors (gensym)))
    `(let ((,actors (list ,@fns)))
       (mapcar #'(lambda (x) (format t "Actor (type ~a): [~a]~&" (type-of x) x)) ,actors)
       (defun ,name (in out &optional (pos 0))
         (assert (stringp in))
         (assert (streamp out))
         (assert (or (plusp pos) (zerop pos)))
         (loop for actor in ,actors
               when (funcall actor in out pos)
               return it)))))

这基本上不需要是一个宏。您主要可以使用辅助功能:

(defun make-actor (&rest funs)
  (lambda (in out &optional (pos 0)
    (loop for actor in funs
      when (funcall actor in out pos) return it)))
并编写一个简单的宏:

(defmacro defactor (name &rest funs)
  `(let ((f (make-actor ,@funs)))
      (defun ,name (in out &optional (pos 0)) (funcall f in out pos))))
然而,这在表达能力(你实际上像调用函数一样调用宏)或效率(编译器必须非常聪明地解决如何通过倾斜一堆复杂的东西来改进代码)方面并没有什么好处


下面是另一种实现类似的方法:

(defmacro defactor (name (in out pos) &rest actors)
  (let ((inv (gensym "IN"))
        (outv (gensym "OUT"))
        (posv (gensym "POS")))
    `(defun ,name (,inv ,outv &optional (,posv 0))
        ;; TODO: (declare (type ...) ...)
        (or ,@(loop for form in actors 
                 collect `(let ((,in ,inv) (,out ,outv) (,pos ,posv)) ,form)))))
然后像这样使用它:

(defactor invert-case (in out pos)
  (let ((ch (char str pos)))
    (when (upper-case-p ch)
      (format out "~a" (char-downcase ch))
      (1+ pos)))
  (let ((ch (char str pos)))
    (when (lower-case-p ch)
      (format out "~a" (char-upcase ch))
      (1+ pos))))

您可以用
(list,@fns)
@jkiiski替换循环,不幸的是,这不起作用:
;LET绑定规范(MAPCAR;#’(LAMBDA(X);(格式T“Actor(type~a):[~a]~&”(type-OF X)X));#:G647)的格式不正确。
这听起来像是LET绑定缺少一个右括号,所以它也将下面的
MAPCAR
表单作为绑定;LET绑定规范(反吹倒壳(输入输出和可选(位置0))…的格式不正确。
它的作用是什么?对于这个简单的例子来说,看起来非常复杂。Dan Robertson,你的观察的确很有趣。现在我将用第一个解决方案来说明问题,因为
过程线
将与由不同宏创建的参与者一起工作,而不仅仅是
defactor
(我在
deftransformer
中重命名了它)。
(defmacro defactor (name (in out pos) &rest actors)
  (let ((inv (gensym "IN"))
        (outv (gensym "OUT"))
        (posv (gensym "POS")))
    `(defun ,name (,inv ,outv &optional (,posv 0))
        ;; TODO: (declare (type ...) ...)
        (or ,@(loop for form in actors 
                 collect `(let ((,in ,inv) (,out ,outv) (,pos ,posv)) ,form)))))
(defactor invert-case (in out pos)
  (let ((ch (char str pos)))
    (when (upper-case-p ch)
      (format out "~a" (char-downcase ch))
      (1+ pos)))
  (let ((ch (char str pos)))
    (when (lower-case-p ch)
      (format out "~a" (char-upcase ch))
      (1+ pos))))