【问题标题】:Lexical Bindings in Common Lisp MacrosCommon Lisp 宏中的词法绑定
【发布时间】:2018-08-21 01:12:29
【问题描述】:

我目前正在研究 Graham 的 On Lisp,发现这个特别难理解:

绑定。词法变量必须直接出现在源代码中。这 例如,setq 的第一个参数没有被评估,所以任何东西 建立在setq 上的必须是一个扩展为setq 的宏,而不是一个 调用它的函数。对于像let 这样的运算符也是如此,其 参数将作为参数出现在 lambda 表达式中,因为 像 do 这样的宏会扩展为lets,等等。任何新的运营商 这是改变其参数的词法绑定必须是 写成宏。

这来自第 8 章,其中描述了何时应该和不应该使用宏来代替函数。

他在这一段中究竟是什么意思?有人能举一两个具体的例子吗?

非常感谢!

【问题讨论】:

  • 作为 Lisper 的经验者,我完全理解该文本 试图 说什么,只是我无法解析实际文本。如果我用手指从段落中间滑过,然后在 0.5 秒内略过它,那是有道理的,但如果我挑出单个单词和短语,那我就有点想不开了。
  • 例如,let 的“参数”不会出现在 lambda 表达式中。什么?
  • 你是说写得不好?这一段是一个段落的例子,无论我读了多少遍,我仍然问自己,“什么?”

标签: macros lisp common-lisp lexical-scope


【解决方案1】:

setq 是一种特殊形式,不会计算其第一个参数。因此,如果你想创建一个更新某些东西的宏,你不能这样做:

(defun update (what with)
  (setq what with))

(defparameter *test* 10)
(update *test* 20)        ; what does it do?
*test*                    ; ==> 10

所以在函数updatesetq 内部将变量what 更新为20,但它是一个局部变量,其值10 会被更新,而不是*test* 本身。为了更新*test* setq 必须有*test* 作为第一个参数。宏可以做到这一点:

(defmacro update (what with)
  `(setq ,what ,with))

(update *test* 20)        ; what does it do?
*test*                    ; ==> 20

您可以从宏扩展中准确看到生成的代码:

(macroexpand-1 '(update *test* 20))
; ==> (setq *test* 20) ; t

类似的例子。您不能使用函数模仿 ifcond

(defun my-if (test then else)
  (cond (test then)
        (t else)))

(defun fib (n)
  (my-if (< 2 n) 
         n
         (+ (fib (- n 1)) (fib (- n 2)))))

(fib 3)

无论你传递什么参数,你都会得到一个无限循环,总是调用递归情况,因为所有my-if 参数总是被评估。使用 condif 时,test 会被评估,并基于此评估 thenelse,但绝不会无条件地评估。

【讨论】:

    猜你喜欢
    • 2019-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-08
    • 1970-01-01
    • 1970-01-01
    • 2016-10-27
    • 2011-04-27
    相关资源
    最近更新 更多