迷茫的宏定义

xie*_*pan 4 macros common-lisp sicp lazy-sequences

我想在SICP第3.5.1节中实现延迟流

首先,我定义了这两个功能

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

(defun force (form)
  (when form
    (funcall form)))
Run Code Online (Sandbox Code Playgroud)

当我们打电话:

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

(force (delay (+ 1 2)))
;;=> 3
Run Code Online (Sandbox Code Playgroud)

这样才有用.然后我继续定义`stream-cons',但这次似乎有两种方式:

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

(defmacro stream-cons (a b)
  `(cons ,a (delay ,b)))
Run Code Online (Sandbox Code Playgroud)

我不认为他们是不同的,但我错了!第一版,这是一个错误的版本,当被称为:

(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}>)
Run Code Online (Sandbox Code Playgroud)

和第二版,这是正确的,当被称为:

(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)))
Run Code Online (Sandbox Code Playgroud)

现在,我很困惑.谁能帮助我弄清楚两者的不同之处?非常感谢!

我的环境:Windows 32位,SBCL 1.1.4

Vse*_*kin 7

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

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

你可以这样画:

,(delay '(progn (print "hello") 2)) => (lambda () '(progn (print "hello") 2))
Run Code Online (Sandbox Code Playgroud)

在第二个变体中(delay ,b):

(delay ,'(progn (print "hello") 2)) => (delay (progn (print "hello") 2))
Run Code Online (Sandbox Code Playgroud)

这里的问题是宏调用的参数是字面上传递的,没有评估.因此,delay有效地接收引用列表('(progn (print "hello") 2)).如果他们见面,逗号做的是取消引用.