Reputation: 66650
I have macro let-- (like let* using lambdas) in guile:
(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))
it works fine when I use an external function to do code generation, but the code below (with is just a macro) doesn't work:
(define-macro (let-- pairs . body)
(if (null? pairs)
`((lambda () ,@body))
`((lambda (,(caar pairs))
,(let-- (cdr pairs) body))
,(cadar pairs))))
why?
Upvotes: 1
Views: 167
Reputation: 48775
I think Joshua nailed the answer to you problem. I just want to point out that Scheme
standard use syntax-rules
and syntax-case
. It could be something like like this with 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)
Upvotes: 2
Reputation: 85913
In the second, you don't want
,(let-- (cdr pairs) body)
but rather
(let-- ,(cdr pairs) ,@body)
That is, your direct macro implementation should be
(define-macro (let-- pairs . body)
(if (null? pairs)
`((lambda () ,@body))
`((lambda (,(caar pairs))
(let-- ,(cdr pairs) ,@body))
,(cadar pairs))))
You don't want to evaluate the inner (let-- ...)
at macro expansion time; it's part of the source that should be generated. (Of course, it will be macroxpanded very shortly after.) To highlight this, consider a macro that turns
(plus a b c d)
into
(+ a (+ b (+ c d)))
It would need to expand like
(+ ,(car args) (plus ,@(cdr args)))
but not
(+ ,(car args) ,(plus (cdr args)))
because the latter will try to evaluate (plus '(b c d))
, which won't work.
Upvotes: 3
Reputation: 60074
Here is a working Common Lisp version:
(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
The corresponding Scheme version is, I guess,
(define-macro (let-- pairs . body)
(if (null? pairs)
`((lambda () ,@body))
`((lambda (,(caar pairs))
(let-- ,(cdr pairs) . ,body))
,(cadar pairs))))
Upvotes: 1