迷茫的宏定义

时间:2013-05-30 03:45:34

标签: macros common-lisp sicp lazy-sequences

我想在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

1 个答案:

答案 0 :(得分:7)

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

问题是,(delay b)是在宏展开时评估的,即lambda是在适当的位置创建的,并且被包裹在传递给它的文字值上,这是列表的符号。因此,您将获得一个始终返回相同值的常量函数 - 恰好是您的代码的列表。

你可以这样画画:

,(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))。如果他们见面,逗号的作用就是取消引用。