![](/img/trans.png)
[英]Why does this Lisp macro as a whole work, even though each piece doesn't work?
[英]Why this lisp recursive macro doesn't work?
我在guile中有宏let-(例如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))))
为什么?
在第二,你不想
,(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 '(bcd))
,这将无法正常工作。
我认为约书亚为您解决了问题。 我只想指出, Scheme
标准使用syntax-rules
和syntax-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)
这是一个有效的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))))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.