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

How to let macros work without defining what a macro is...



Even though it was not possible to agree on how macros
should be specified in Scheme, I believe it important
that they be provided in some form in all implementations
and have a proposal for a semi-invisible way to do this.

(PRIMITIVE-SYNTAX-EXPAND form)		required

 Takes any form and returns a form which is guaranteed
 not to have any syntax other than that required by
 the language.

 This function signals an error if it receives a form
 which is a user-defined macro. (Hence, this function is
 for writing code which is defined only over portable 
 code). The fact that it only allows "primitive" macros
 to be expanded is what makes it not need an ENV argument,
 since the primitive language does not allow one to
 change the set of special forms.

 Actually, there are two variations of this proposal which
 are probably consistent. One says that it expands all 
 levels; the other says that it expands just one level.
 I think it really doesn't matter. For consistency with
 SYNTAX-EXPAND below, let's assume it doesn't recurse into
 the form.

The intent is (though this is not part of the proposal)
that languages providing a macro facility would have a
function:

(SYNTAX-EXPAND form env)		optional

 Takes any form and a syntax environment and returns
 a form which has no other syntax than lisp syntax.

 This form will expand macros and call PRIMITIVE-SYNTAX-EXPAND
 if the underlying representation makes that necessary. 
 The result should be a form which contains only primitive forms.

This would allow us to define system extensions which we could
-describe- as macro translations without telling users how those
things were defined. Eg, they might be macros or they might be
special forms. Consider that (function/macro names in this example
being hypothetical, but you'll get the idea I hope):

 (WITH-OPEN-FILE (STREAM-VAR FILE-NAME . OPTIONS) . BODY)

might be defined to the user to "be the same as":

 (CALL-WITH-OPEN-STREAM (LAMBDA (STREAM-VAR) BODY) FILE-NAME . OPTIONS)

and

 (PRIMITIVE-SYNTAX-EXPAND 
    '(WITH-OPEN-FILE (OUTSTREAM "MY.FILE" 'OUT)
       (PRINT "Hi there." OUTSTREAM)))

would be defined to return

 (CALL-SYNTAX-EXPAND (LAMBDA (OUTSTREAM) (PRINT "Hi there." OUTSTREAM))
		     "MY.FILE" 'OUT)

regardless of whether the system actually did that expansion when it 
ENCLOSEd the form...

This proposal basically gives the user the ability to maintain the
illusion that there are a fixed set of special forms when he does
code-manipulation even if we later decide that a few extra special forms
would be a good idea. eg, WHEN, UNLESS, etc. would not burden code-walking
writers since (PRIMITIVE-SYNTAX-EXPAND form) would know about those
forms and how to magically make them into something meaningful like COND
or IF (are they both primitive? they wouldn't have to be under this proposal).

This also allows implementations to add new special forms which are not
in standard Scheme but which are still handleable by standard Scheme.

Note well that programs which expect to work on code which might call
user-defined macros would HAVE TO use SYNTAX-EXPAND and could not use
PRIMITIVE-SYNTAX-EXPAND even if PRIMITIVE-SYNTAX-EXPAND would appear to
work, since PRIMITIVE-SYNTAX-EXPAND should NOT be sensitive to any
redefinitions of system primitive special forms that extended Scheme
implementations might allow. That is, if a dialect allowed
 (DEFINE-SYNTAX (IF ...) ...variant-definition...)
then
 (SYNTAX-EXPAND '(IF ...)) should get the variant expansion but
 (PRIMITIVE-SYNTAX-EXPAND '(IF ...)) should get the "standard expansion".
This is completely necessary in order for any of this proposal to make sense.