Common Lisp未绑定变量/ defmacro

时间:2013-09-28 15:52:47

标签: variables lambda common-lisp

我需要为我的元循环解释器创建函数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.

我无法理解为什么。

- - - - - - - - EDITED 如果我用这个:

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

2 个答案:

答案 0 :(得分:0)

您的my-defmacro适用于托管CL系统,但我觉得您希望在解释器中使用宏功能,但这样做不会。 (除非解释器环境是全局主机实现环境,否则会带来很多挑战)

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

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

复合过程和复合语法之间的真正区别在于,为过程评估参数,并在复合语法中评估结果。

因此。你实现了((lambda(x)(+ x x))5)有效吗?好吧,那么你几乎也会实现宏。对于编译器来说当然不是这样,因为这种方法会在每次运行时扩展代码,而不是在创建闭包时扩展一次。 (无论如何,优化都无法进入第一个版本)

答案 1 :(得分:0)

对于你的“编辑过的代码”,你有一个错位的paren:

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