macros - 为什么使用 "let"的宏与不使用的宏展开方式不同?

标签 macros lisp common-lisp let

我是 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 被反引号括起来,所以我认为这意味着它不会被评估。在没有宏扩展的情况下评估 niffyniffy2 都完全按照我的预期工作,为正、零和负返回“正”、“零”和“负”值分别。

最佳答案

这是因为 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/

相关文章:

c - 如何在 C 中的多维数组上实现 foreach 循环?

lisp - 用最后一个元素替换子列表

tree - 如何获取n叉树中节点的路径?

common-lisp - 用于解析无效 HTML 的 Common Lisp 包?

arrays - 如何拥有两个相等但内部状态不同的数组

c++ - 如何调用包含参数集的笛卡尔积中所有点的宏?

c++ - 在 if-else if 链中使用 Likely()/Unlikely() 预处理器宏

用于重复使用 std::xyz 语句的 C++ 宏

scheme - 为什么使用 list 或 cons 构建时相同的数据打印不同?

list - 口齿不清。创建对列表