我是 Lisp 的新手,我正在阅读 Doug Hoyte 的 Let Over Lambda,他在第 3 章介绍了 Paul Graham 的 nif
宏。我正在研究它并制作了这两个宏:
(defmacro niffy (expr pos zero neg)
`(cond ((plusp ,expr) ,pos)
((zerop ,expr) ,zero)
(t ,neg)))
(defmacro niffy2 (expr pos zero neg)
`(let ((x ,expr))
(cond ((plusp x) ,pos)
((zerop x) ,zero
(t ,neg)))))
当我执行 (macroexpand '(niffy2 10 "positive""zero""negative"))
时,我得到了我期望的结果:(LET ((X 10)) (COND ((PLUSP X)“正”)((ZEROP X)“零”(T“负”))))
但是当我执行 (macroexpand '(niffy 10 "positive""zero""negative"))
时,我只是得到评估形式 "positive"
。这让我感到困惑,因为在 niffy
中,cond
被反引号括起来,所以我认为这意味着它不会被评估。在没有宏扩展的情况下评估 niffy
和 niffy2
都完全按照我的预期工作,为正、零和负返回“正”、“零”和“负”值分别。
最佳答案
这是因为 cond
是一个宏。尝试运行以下命令:
(macroexpand
'(cond ((plusp 10) "positive")
((zerop 10) "negative")
(t "zero")))
在 SBCL 中,我得到了这个:
(IF (PLUSP 10)
(PROGN "positive")
(COND ((ZEROP 10) "negative") (T "zero")))
T
在 CLISP 中,我得到了这个:
"positive" ;
T
虽然我可以理解 CLISP 的行为,但它似乎有点不必要,因为在宏扩展之后可以更轻松地处理优化。
(请注意,您通常应该更喜欢带有 let
的版本,因为它不会多次计算其参数。)
关于macros - 为什么使用 "let"的宏与不使用的宏展开方式不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28911229/