This is the mail archive of the
kawa@sourceware.org
mailing list for the Kawa project.
Re: question about define-syntax
- From: Luis Casillas <luis at casillas dot org>
- To: Yaroslav Kavenchuk <kavenchuk at gmail dot com>
- Cc: kawa <kawa at sourceware dot org>
- Date: Fri, 8 Feb 2008 09:30:08 -0800
- Subject: Re: question about define-syntax
- References: <47AC4438.5000006@gmail.com>
Inline comments.
On Feb 8, 2008, at 3:59 AM, Yaroslav Kavenchuk wrote:
The simplified example:
;; convert list to list of pairs
(define-syntax make-pair-list
(syntax-rules ()
((_ any)
(error "Broken arguments count for pair-list"))
((_ name value)
(cons (cons name value) ()))
((_ name value . args)
(cons (cons name value) (make-pair-list . args)))))
;; call function with list of pairs
;; this is wrong:
(define-syntax func-with-pairs
(syntax-rules ()
((_ func . args)
(func . (make-pair-list . args)))))
;; result of (func-with-pairs list 1 2 3 4)
;; is (#<macro make-pair-list> 1 2 3 4), not ((1 . 2) (3 . 4)
The macro expander is doing something like the following:
(func-with-pairs list 1 2 3 4)
;; func-with-pairs is a syntactic keyword; expand expression
=> (list . (make-pair-list 1 2 3 4))
;; but the previous expression is equivalent to the following
=> (list make-pair-list 1 2 3 4)
Since make-pair-list is not in the first position of the syntax form,
it never triggers expansion. The use of the dot notation confuses
the situation, since it makes it look like make-pair-list will get
expanded.
;; this is right
(define-syntax func-with-pairs
(syntax-rules ()
((_ func . args)
(apply func (make-pair-list . args)))))
;; but why need `apply`?
(func-with-pairs list 1 2 3 4)
=> (apply list (make-pair-list 1 2 3 4))
=> (apply list (cons (cons 1 2) (cons (cons 3 4) ())))
How write macro without `apply`?
I'm still thinking how to do it simply with syntax-rules. If you
know syntax-case (and yes, I know, that's a big "if"), it's a lot
easier that way. I just got the following to work in PLT Scheme, but
it's certainly going to need some modification to work in Kawa
(sorry, I can't try it in Kawa just now):
(define-syntax func-with-pairs
(lambda (stx)
(syntax-case stx ()
((_ fn . rest)
(odd? (length (syntax-object->datum #'rest)))
(error "func-with-pairs must have an even number of arguments"))
((_ fn . rest)
(with-syntax ((conses (make-pair-list #'rest)))
(syntax
(fn . conses)))))))
;; Kawa doesn't have define-for-syntax; just use define
(define-for-syntax (make-pair-list stx)
(syntax-case stx ()
(()
(syntax ()))
((a b . rest)
(with-syntax ((rest-conses (make-pair-list #'rest)))
(syntax
((cons a b) . rest-conses))))))
Trying it at the REPL:
> (func-with-pairs list 1 2 3 4)
((1 . 2) (3 . 4))
> (require (lib "pretty.ss"))
> (pretty-print (syntax-object->datum (expand '(func-with-pairs list
1 2 3 4))))
(#%app
(#%top . list)
(#%app (#%top . cons) (#%datum . 1) (#%datum . 2))
(#%app (#%top . cons) (#%datum . 3) (#%datum . 4)))
The latter is exactly the same as the PLT primitive expansion of this:
(list (cons 1 2) (cons 3 4))
...which we can also verify:
> (pretty-print (syntax-object->datum (expand '(list (cons 1 2)
(cons 3 4)))))
(#%app
(#%top . list)
(#%app (#%top . cons) (#%datum . 1) (#%datum . 2))
(#%app (#%top . cons) (#%datum . 3) (#%datum . 4)))
The lesson I've learned about macros in Scheme: syntax-case is really
hard to learn in the short term, but easier in the long run than
syntax-rules.