[gambit-list] Proposal for lightweight real hygienic macros in Gambit

Per Eckerdal per.eckerdal at gmail.com
Mon Apr 2 07:23:30 EDT 2012


On Saturday 31 March 2012 at 13:23, Mikael wrote:
> Hi Per,
>  
> What's |alias|' scope - just to doublecheck I got your point, is it, that it expands the passed identifier to the fully qualified name form (i.e. the complete and non-overlappable form), of the identifier with that name that is defined the most closely upwards in the lexical scope from the point where |alias| is used?
Yeah.. I think that's right. |alias| uses the same scope as where the form is written.
> I suppose that's how it is. So the following
>  
> (define a 0)
> (alias a)
> (define a -1)
> (alias a)
> (let ((a 0))
>    (define-macro (somename) (alias a))
>    (define a 1)
>    (define-macro (somename) (alias a) (let ((a 2)) (alias a))))
>    (define a 3)
>    (define-macro (b) (alias a))
>    (let ((a 4))
>       (alias a)
>       (b))))
>  
> would expand to (a functional equivalent of)
>  
> (define 0#a 0)
> 0#a
> (define 1#a -1)
> 1#a
> (let ((2#a 0))
>    (define-macro (somename) 2#a)
>    (define 3#a 1)
>    (define-macro (somename) 3#a (let ((4#a 2)) 4#a)))
>    (define 5#a 3)
>    (define-macro (somename) 5#a)
>    (let ((6#a 4))
>       6#a
>       5#a)))
>  
> ?
Almost, but not quite. Duplicate definitions on the top level in the REPL should overwrite each other, not create separate bindings. So if you're in the "mod#" namespace, both top level definitions of a should expand into (define mod#a …). This is consistent with Gambit's current behavior.

Multiple defines of the same variable name within a scope, like 3#a and 5#a in your example, is not legal Scheme. If Black Hole allows this syntax, it's a bug in Black Hole. Gambit rejects the code with a "Duplicate definition of a variable" message.

Other than that, yes, that's how it should work.
> Are there any key aspects of |alias|' renaming function that the above example does not illustrate, if so which?
No. The rules are really simple. The cases that you bring up that are non-obvious are not legal Scheme, so they don't need to be considered.
> And thus, we get a mechanism for syntax-rules-style hygiene i.e.
>  
> ; (Here neither cons nor error are overlapped, but Gambit's defaults)
> (define-syntax real-cons (syntax-rules () ((real-cons a b) (cons a b))))
> (define cons error)
> (real-cons 1 2)
>  
> can as well be written
>  
> ; (Here neither cons nor error are overlapped, but Gambit's defaults)
> (define-macro (real-cons a b) `(,(alias cons) ,a ,b))
> (define cons error)
> (real-cons 1 2)
>  
> , both expanding to (a functional equivalent of)
>  
> (define 2#cons #error) ; #error as in, Gambit's standard |error|
> (#cons 1 2) ; #cons as in, Gambit's standard |cons|
>  
> Correct?
Yes, both the syntax-rules macro and the define-macro macro would be equivalent (possibly except for error handling and source code location information).

Your statement about this being syntax-rules-style hygiene isn't really correct, though: One of the main points with syntax-rules is that you don't need gensym. With this macro system, you still need to explicitly use gensym.

The reason for this is that you can't use |alias| when you bind names:

(define-macro (mac code)
  `(,(alias let) ((,(alias a) 'a)) ,code ,(alias a)))

The code snippet above isn't necessarily hygienic. You need gensyms for hiding any names that macros bind. And AFAIK there is no way of doing that automatically with this system: For that you need to introduce a new identifier data type, like syntactic closures, explicit renaming and syntax-case do.

Per

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.iro.umontreal.ca/pipermail/gambit-list/attachments/20120402/4c425438/attachment.htm>


More information about the Gambit-list mailing list