Macros 是否可以编写以下lisp宏作为函数?

Macros 是否可以编写以下lisp宏作为函数?,macros,common-lisp,Macros,Common Lisp,我在看书。在关于宏的章节中,他展示了以下示例: (defmacro in (obj &rest choices) (let ((insym (gensym))) `(let ((,insym ,obj)) (or ,@(mapcar #'(lambda (c) `(eql ,insym ,c)) choices))))) (如果第一个参数等于任何其他参数,则返回true) 他认为它不能写成函数。这个函数不具有相同的功能吗

我在看书。在关于宏的章节中,他展示了以下示例:

(defmacro in (obj &rest choices)
  (let ((insym (gensym)))
   `(let ((,insym ,obj))
      (or ,@(mapcar #'(lambda (c) `(eql ,insym ,c))
                    choices))))) 
(如果第一个参数等于任何其他参数,则返回true)

他认为它不能写成函数。这个函数不具有相同的功能吗

(defun in (obj &rest choices)
  (reduce (lambda (x y)
            (or x (eql y obj)))
          choices
          :initial-value nil))

我看到的区别是,宏在找到eql参数之前只对参数求值。是吗?

关键是,如果找到匹配项,宏版本将延迟(扩展为OR)计算参数。这不能通过函数实现,因为funcall总是首先计算所有参数

> (macroexpand '(in 42
                    (long-computation-1)
                    (long-computation-2)
                    (long-computation-3)))

(LET ((#:G799 42))
  (OR (EQL #:G799 (LONG-COMPUTATION-1))
      (EQL #:G799 (LONG-COMPUTATION-2))
      (EQL #:G799 (LONG-COMPUTATION-3))))
要获得相同的效果,您需要编写:

(defun in (obj &rest choices)
  (reduce (lambda (x y)
             (or x (eql (funcall y) obj)))
          choices
          :initial-value nil))
并以这种方式使用它:

(in 42
    (function long-computation-1)
    (function long-computation-2)
    (function long-computation-3))
这是一个相当大的“是吗?”。如果有人说“我可以给你一个
If
,那不是一个宏,只是一个函数!(但它总是计算两个分支。)”,你会说“是吗?”