[plt-scheme] Dot-notation for structure field access
Hi Matthew
Thanks, that 's quick and clear. It took you less time for you to answer me than for me to read your answer. Thanks, Jos Koot.
(Warning to others: module dot should be discouraged because it has some nasty shortcomings I am still working on. To solve these shortcomings requires runtime registers too. They cannot be solved in the expansion phase)
(((((lambda(x)((((((((x x)x)x)x)x)x)x)x))
(lambda(x)(lambda(y)(x(x y)))))
(lambda(x)(x)x))
(lambda()(printf "Greetings, Jos~n"))))
----- Original Message -----
From: Matthew Flatt
To: jos koot
Cc: plt-scheme at list.cs.brown.edu
Sent: Monday, March 19, 2007 7:56 AM
Subject: Re: [plt-scheme] Dot-notation for structure field access
At Sun, 11 Mar 2007 12:49:17 +0100, "jos koot" wrote:
> Inspired by the dot notation of Jens Axel Søgaard I tried to eliminate the
> need for define-accessor. See enclosure. However, I can't get rid of the error
> reported at the end of my trial, reading:
> "compile: bad syntax; reference to top-level identifier is not allowed,
> because no #%top syntax transformer is bound in: acc85"
The problem starts here:
(define-syntax (define-struct-type stx)
(syntax-case stx ()
....
((define-struct-type (descr constr pred super) (field ...) inspector)
(let-values (((acc mut) (apply values (generate-temporaries #'(acc mut)))))
(register-transformer-builder #'constr #'(field ...) acc mut)
#`(define-values (descr constr pred #,acc #,mut)
....)))))
The call to `register-transformer-builder' is a side effect that
happens while the macro is expanded. After a `define-struct-type' form
is expanded --- say, when compiling a module --- the side-effect won't
happen anymore. In particular, the side effect won't happen if you
(next week, on a different machine) load the compiled form of module
whose source contains the `define-struct-type' declaration.
Well, the error you see is only indirectly related to the problem,
which is partly why it's difficult to track down. The problem is that
the registration uses `acc' and `mut' identifiers before any such
bindings exist, and that leads to the bad reference.
The solution to both problems is the same, and it's simple to write
down:
(define-syntax (define-struct-type stx)
(syntax-case stx ()
....
((define-struct-type (descr constr pred super) (field ...) inspector)
(let-values (((acc mut) (apply values (generate-temporaries #'(acc mut)))))
#`(begin
(begin-for-syntax
(register-transformer-builder #'constr #'(field ...) #'#,acc #'#,mut))
(define-values (descr constr pred #,acc #,mut)
....))))))
All I've done is move the `register-transformer-builder' call into the
result of the macro, so that it's a side-effect wrapped by
`begin-for-syntax'. Since it's part of the result expansion, the side
effect happens each time the expanded (or compiled) expression is
loaded.
Moreover, `acc' and `mut are now in the same binding context as the
`define-values' form, so they get bound in the way that you want.
The general rule is: Don't put any side-effects in a macro expansion.
If you must have side effects at compile time, they should be in
`begin-for-syntax'.
See also
http://www.cs.utah.edu/plt/publications/macromod.pdf
which may make more sense now that you've hit the problem that it
describes. :)
Unfortunately, there's a small catch, which I think is almost certainly
related to your later question about `syntax-recertify'. If you try
(module m mzscheme
(require dot)
(define-struct-type d c p (x y z) (make-inspector))
(provide d c p))
(module n mzscheme
(require dot m)
(define-struct-var s (c 1 2 add1))
(printf "~s\n" s.x))
then you get
compile: access from an uncertified context to unexported variable
from module: m at: acc1 in: acc1.1
Even though there's no `local-expand' in the macro implementation,
there is a kind of manual expansion that happens when looking up a
binding via `register-lookup'. That manual lookup must be accompanied
by manual management of certificates (though not through using
`syntax-recertify').
So, explicitly certify the referencing identifiers before you record
them:
(define-syntax (define-struct-type stx)
(syntax-case stx ()
....
((define-struct-type (descr constr pred super) (field ...) inspector)
(let-values (((acc mut) (apply values (generate-temporaries #'(acc mut)))))
#`(begin
(begin-for-syntax
(let ([cert (syntax-local-certifier)])
(register-transformer-builder #'constr #'(field ...)
(cert #'#,acc)
(cert #'#,mut))))
(define-values (descr constr pred #,acc #,mut)
....))))))
Revised code and example enclosed.
Matthew
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20070319/316d10fa/attachment.html>