我正在尝试在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语句不起作用。我认为这是因为我使用了两个级别的间接 - 指的是我在宏中创建的变量。但我似乎无法弄清楚如何解决它!有什么想法吗?
答案 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))