【问题标题】:Common Lisp unbound variable / defmacroCommon Lisp 未绑定变量/defmacro
【发布时间】:2013-09-28 15:52:46
【问题描述】:

我需要为可以读取此语法的元循环解释器创建函数 defmacro:

pseudoscheme> (defmacro (minus x y) (list ‘- y x))
MINUS


pseudoscheme> (expand-macro '(minus 3 2))
(- 3 2)

当我使用这个时:

(defmacro my-defmacro ((name &rest args) &body  body)
    (let ((form (gensym))(env (gensym)))
        (progn 
        `(setf (macro-function ',name)    
            (lambda (,form ,env))
                (destructuring-bind ,args (rest, form) ,@body))
        name
        )   
    )
)

然后:

(my-defmacro (min a b)(list '- a b))

我收到此错误:

Error: The variable MIN is unbound.

我不明白为什么。

-----已编辑----- 如果我使用这个:

(defmacro my-defmacro ((name &rest args) &body  body)
    (let ((form (gensym))(env (gensym)))
        `(progn (setf (macro-function ',name)
            (lambda (,form ,env))
                (destructuring-bind ,args (rest, form) ,@body))
         ',name)    
    )
)

然后:

(my-defmacro (min a b)(list '- a b))

我收到此错误:

Error: Odd number of args to SETF: ((MACRO-FUNCTION (QUOTE PLUS)) (LAMBDA (#:G786 #:G787)) (DESTRUCTURING-BIND (A B) (REST #:G786) (LIST # A B)))

【问题讨论】:

  • 我们也不行。 PLUS 第一次出现在这个问题中是在您的错误消息中。它不会出现在您的代码中任何地方。您没有显示使用您实际使用的代码。此外,您说您希望能够做到(defmacro (minus x y) (list ‘- y x)),但实际上您做到了(my-defmacro (min a b)(- a b))。请按照你说的去做,然后向我们展示结果。
  • 这与您的其他问题几乎相同的内容有什么不同redefine defmacro in LISP
  • 不管所有其他事情,你不需要在let 中使用prognlet 已经充当隐式progn
  • @Joshua Taylor,更正了问题,无论如何问题都是一样的。我使用 my-defmacro 只是为了避免重新定义我的 defmacro 函数的请求,但如果我可以使用 defmacro 而不是 my-defmacro 可能会更好。
  • @Sylwester 我已经要求(向版主举报)关闭该问题,因为我犯了一个大错误,我不知道如何让一切更清楚:/

标签: variables lambda common-lisp


【解决方案1】:

您的my-defmacro 为您托管 CL 系统工作,但我感觉您希望在解释器中具有宏功能,但这样做不会。 (除非解释器环境是全局宿主实现环境,但这会带来很多挑战)

我不知道您如何在评估器中执行复合程序,但是当我的评估器获得(lambda (x) (+ x x)) 时,它会变成(compound-procedure <env> (x) (+ x x))。除了第一个元素是compound-syntax,我的宏几乎变成了相同的。

每个评估的运算符都有一个标签,告诉它它是什么(原始语法、原始过程、复合语法、复合过程之一),我只需要处理这 4 个的一般方法。

复合过程和复合语法之间的真正区别在于,参数是为过程计算的,而在复合语法中,结果是被计算的。

所以。您是否已实现 ((lambda (x) (+ x x)) 5) 工作?好吧,那么您几乎也将实现宏。对于编译器来说当然不是这样,因为这种方法会在每次运行时扩展代码,而不是在创建闭包时扩展一次。 (反正第一个版本优化是不行的)

【讨论】:

  • 自定义的 defmacro 不起作用。请注意,它只是返回name,而不是设置宏函数的表单。这就是发生错误的原因。它需要是 `(progn (setf ...) ',name)。
【解决方案2】:

对于您的“已编辑代码”,您有一个放错位置的括号:

(defmacro my-defmacro ((name &rest args) &body  body)
    (let ((form (gensym))(env (gensym)))
        `(progn (setf (macro-function ',name)
            (lambda (,form ,env))                    ;; <== HERE
                (destructuring-bind ,args (rest, form) ,@body))
         ',name)    
    )
)

这导致setf 具有三个子表单。像这样重写它(同时使用标准的 Lisp 格式):

(defmacro my-defmacro ((name &rest args) &body  body)
  (let ((form (gensym))
        (env  (gensym)))
    `(progn (setf (macro-function ',name)
                  (lambda (,form ,env)
                    (destructuring-bind ,args (rest, form) 
                      ,@body)))
            ',name)))   

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多