[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

macros expanding into definitions




The other day I was trying to define a macro (using R5RS
DEFINE-SYNTAX) that expanded into multiple definitions.  What I wanted
was for

	(define-multiple (a b c)
	  (let etc. etc. (values x y z)))

to define a to be x, b to be y, and c to be z.  In general,
(define-multiple (name ...) exp) should evaluate expression exp
(once), and then bind the variables name ... to the values delivered
by exp.  The number of values must match the number of names.  The
obvious implementation is

	(define-syntax define-multiple
	  (syntax-rules ()
	    ((define-multiple (name ...) exp)
	     (begin (define name #f) ...
		    (call-with-values (lambda () exp)
		      (lambda vals
		        (begin (set! name (car vals))
			       (set! vals (cdr vals)))
			...))))))

but the problem is that the expansion doesn't parse.  The report says
that a top-level form must be either a definition or an expression,
and a BEGIN form that contains both, is neither.

	<expression> ::= (begin <expression>*)
	<definition> ::= (begin <definition>*)

Even worse, this has no hope of working in place of an internal DEFINE.

Now, the following rewrite sort of works:

	(define-syntax define-multiple
	  (syntax-rules ()
	    ((define-multiple (name1 name ...) exp)
	     (begin (define name #f) ...
		    (define name1
		      (call-with-values (lambda () exp)
			(lambda vals
			  (let ((temp (car vals))
			        (vals (cdr vals)))
			    (begin (set! name (car vals))
				   (set! vals (cdr vals)))
			    ...
			    temp))))))))

Rather a kludge, but now it parses as a definition, and it should work
at top level, because definitions are supposed to be evaluated in the
sequence in which they occur syntactically.

But still no hope of working as an internal definition, because the
order of evaluation isn't specified there: if the definition for name1
is performed *before* any of the other definitions, choas will ensue.
Even worse, the rule that it is an error to SET! a variable bound by a
LETREC until all the initializers have been evaluated causes the
SET!'s here to lose.

I don't think this is an obscure macro; most of these issues come up
with a define-structure-type macro or any of various module-defining
macros.

Can anyone suggest a workaround for this?  I would like to be able to
use macros like this in contexts that allow internal defines.

Jonathan