2013-05-30 71 views
4

我想實現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 

所以這是有效的。然後我去定義'流禁忌症,但這次 似乎是兩種方式:

(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

回答

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))。如果他們見面,用逗號取消報價。