【问题标题】:confused in a macro definition在宏定义中感到困惑
【发布时间】:2013-05-30 03:45:33
【问题描述】:

我想在 SICP 3.5.1 节中实现惰性流

首先,我定义了这两个函数

(defmacro delay (form)
  `(lambda () ,form))

(defun force (form)
  (when form
    (funcall form)))

当我们打电话时:

(force (delay '(+ 1 2)))
;;=> (+ 1 2)

(force (delay (+ 1 2)))
;;=> 3

这样就成功了。然后我继续定义'stream-cons',但这次有 似乎有两种方式:

(defmacro stream-cons (a b)
  `(cons ,a ,(delay b)))

(defmacro stream-cons (a b)
  `(cons ,a (delay ,b)))

我不认为他们是不同的,但我错了!第一版,其中 调用时是错误的版本:

(force (cdr (stream-cons 'a (progn (print "hello") 2))))
;;=> (PROGN (PRINT "hello") 2)

(macroexpand '(stream-cons 'a (progn (print "hello") 2)))
;;=> (CONS 'A #<CLOSURE (LAMBDA # :IN STREAM-CONS) {25ABB3A5}>)

第二版,当被调用时,这是正确的:

(force (cdr (stream-cons 'a (progn (print "hello") 2))))
;; 
;; "hello" 
;; => 2

(macroexpand '(stream-cons 'a (progn (print "hello") 2)))
;;=> (CONS 'A (DELAY (PROGN (PRINT "hello") 2)))

现在,我很困惑。谁能帮我弄清楚不同 两个?非常感谢!

我的环境:Windows 32 位,SBCL 1.1.4

【问题讨论】:

    标签: macros common-lisp sicp lazy-sequences


    【解决方案1】:

    这是理解宏的一个重要概念。

    问题是 ,(delay b) 在宏扩展时被评估,即 lambda 被创建并包裹在传递给它的 literal 值上,即符号列表。所以你得到一个总是返回相同值的常量函数——一个恰好是你的代码的列表。

    你可以这样画:

    ,(delay '(progn (print "hello") 2)) => (lambda () '(progn (print "hello") 2))
    

    在第二个变种(delay ,b):

    (delay ,'(progn (print "hello") 2)) => (delay (progn (print "hello") 2))
    

    这里的问题是宏调用的参数是按字面意思传递的,没有求值。所以delay 有效地接收到一个引用列表('(progn (print "hello") 2))。逗号的作用是在他们见面时取消报价。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多