[英]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.