为什么这个lisp递归宏不起作用?

时间:2013-10-23 18:28:14

标签: macros lambda lisp scheme guile

我在guile中有一个宏let--(比如让*使用lambdas):

(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))))

为什么?

3 个答案:

答案 0 :(得分: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-- ...);它是应该生成的源的一部分。 (当然,它很快就会被宏观扩展。)为了突出这一点,考虑一个转动的宏

(plus a b c d)

进入

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

需要像

一样扩展
(+ ,(car args) (plus ,@(cdr args)))

但不是

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

因为后者会尝试评估(plus '(b c d)),这将无效。

答案 1 :(得分: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)

答案 2 :(得分: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

相应的Scheme版本,我想,

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