Lisp宏的问题

时间:2011-06-01 07:05:55

标签: macros lisp common-lisp mcl

我正在尝试在Lisp中编写一个使用自身重新实现let的宏。这是一项微不足道的练习,没有实际意义;然而,在给response一个相关问题后,我意识到我应该更多地了解宏。他们被吹捧为Lisp的好东西之一,但我很少使用它们。

无论如何,这是我先试过的:

(defmacro mylet (args &rest exp) `(let ,args (dolist (x ,exp) x)))

但是当我尝试这样的事情时:

 (mylet ((a 5) (b 2)) (print (+ a b)))

这会引发错误:

  #1=(PRINT (+ A B)) is not a symbol or lambda expression in the form (#1#) .

args(a和b)设置正确,但print语句不起作用。我认为这是因为我使用了两个级别的间接 - 指的是我在宏中创建的变量。但我似乎无法弄清楚如何解决它!有什么想法吗?

1 个答案:

答案 0 :(得分:4)

您的宏扩展为:

(LET ((A 5) (B 2))
  (DOLIST (X ((PRINT (+ A B)))) X))

无效,因为((PRINT (+ A B)))不是有效的表达式。还有一个问题是在宏扩展中使用实体符号可能会导致变量捕获,但这并不直接相关(请参阅PCL)。

这里使用DOLIST是不必要的,并且编译为正确(你必须将所有子表单转换为匿名函数以便将它们粘贴在列表中,按顺序执行它们然后存储最终结果以符合PROGN行为)。你可以使用PROGN,或者,因为LET包含一个隐式的PROGN,只需使用反引号机制的@特征来拼接正文:

(defmacro mylet (args &body exp) `(let ,args ,(cons 'progn exp)))

(defmacro mylet (args &body exp) `(let ,args ,@exp))