【问题标题】:Is it possible to write the following lisp macro as a function?是否可以将以下 lisp 宏编写为函数?
【发布时间】:2012-05-13 09:58:05
【问题描述】:

我正在阅读Paul Graham's ANSI Common Lisp。在关于宏的章节中,他展示了以下示例:

(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 参数之前评估参数。是这样吗?

【问题讨论】:

  • 那是一个相当大的“是吗?”。如果有人说“我可以给你一个IF,它不是宏,而只是一个函数!(但它总是评估两个分支。)”,你会说“是吗?”

标签: macros common-lisp


【解决方案1】:

关键是,如果找到匹配项,宏版本会延迟计算参数(它扩展为 OR)停止。这不能通过函数来​​实现,因为函数调用总是首先评估所有参数。

【讨论】:

    【解决方案2】:
    > (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))
    

    【讨论】:

      猜你喜欢
      • 2011-01-07
      • 1970-01-01
      • 2014-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多