2013-10-23 46 views
1

我有宏let--(如讓*使用lambda表達式)在詭詐爲什麼這個lisp遞歸宏不起作用?

(define (let-make-lambdas pairs body) 
    (if (null? pairs) 
     `((lambda() ,@body)) 
     `((lambda (,(caar pairs)) 
      ,(let-make-lambdas (cdr pairs) body)) 
      ,(cadar pairs)))) 

(define-macro (let-- pairs . body) 
    (let-make-lambdas pairs body)) 

它工作正常,當我使用一個外部函數做代碼生成,但下面的代碼(與僅僅是一個宏)不起作用:

(define-macro (let-- pairs . body) 
    (if (null? pairs) 
     `((lambda() ,@body)) 
     `((lambda (,(caar pairs)) 
      ,(let-- (cdr pairs) body)) 
      ,(cadar pairs)))) 

爲什麼?

+0

忘了括號? :P – 2013-10-23 18:30:55

+0

宏調用似乎不符合其定義:點缺失。 – sds

+0

@sds'.'用於定義Common Lisp中的'&rest'列表。在第一種情況下,jcubic正在定義一個函數來執行代碼擴展,並且_macro_ _does_包含'.' –

回答

3

在第二,你不想

,(let-- (cdr pairs) body) 

而是

(let-- ,(cdr pairs) ,@body) 

也就是說,你的直接宏實現應該是

(define-macro (let-- pairs . body) 
    (if (null? pairs) 
     `((lambda() ,@body)) 
     `((lambda (,(caar pairs)) 
      (let-- ,(cdr pairs) ,@body)) 
      ,(cadar pairs)))) 

你不想在宏展開時評估內部(let-- ...);它是應該生成的源的一部分。 (當然,它很快將後macroxpanded。)爲了強調這一點,認爲原來

(plus a b c d) 

(+ a (+ b (+ c d))) 

這將需要擴大像

(+ ,(car args) (plus ,@(cdr args))) 

宏但不是

(+ ,(car args) ,(plus (cdr args))) 

,因爲後者會嘗試評估(plus '(b c d)),這是行不通的。

1

這裏是一個工作的Common Lisp版本:

(defmacro let1-- (pairs . body) 
    (if (null pairs) 
     `((lambda() ,@body)) 
     `((lambda (,(caar pairs)) 
     (let-- ,(cdr pairs) . ,body)) 
     ,(cadar pairs)))) 
> (macroexpand '(let1-- ((a 1) (b 2)) (+ b a))) 
((LAMBDA (A) (LET-- ((B 2)) (+ B A))) 1) ; 
T 
> (let1-- ((a 1) (b 2)) (+ b a)) 
3 

相應的方案版本是,我猜,

(define-macro (let-- pairs . body) 
    (if (null? pairs) 
     `((lambda() ,@body)) 
     `((lambda (,(caar pairs)) 
      (let-- ,(cdr pairs) . ,body)) 
      ,(cadar pairs)))) 
2

我認爲約書亞釘在回答你的問題。我只想指出Scheme標準使用syntax-rulessyntax-case。它可能是這樣的syntax-rules

;; make let* with lambdas 
(define-syntax let-- 
    (syntax-rules() 
    ;; base case, last pair 
    ((let-- ((key1 value1)) . body) 
    ((lambda (key1) . body) value1)) 

    ;; default case, several 
    ((let-- ((key1 value1) . kv-pairs) . body) 
    ((lambda (key1) (let-- kv-pairs . body)) value1)))) 

(let-- ((a 'a) (b a) (c b)) (list a b c)) ; ==> (a a a) 
+0

我更喜歡lisp-macros和支持它們的方案實現,不過謝謝你的回答。 – jcubic