2013-10-23 48 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