[plt-scheme] Attaching compile time information to identifiers
There is a problem with this approach though: because the information
is kept in a table that is in the syntax environment, it is not kept
around for multiple modules. For example, this code (due to Matthew):
(module p mzscheme
(require m)
(f one +))
(module q mzscheme
(require m p)
(display (g one)))
wouldn't work. There is another solution though -- you put the
syntax-level information as the value of a binding. The thing is that
a transformer is just a procedure, so you can make a new struct type
that can be applied as a procedure, but also carries extra information
which is accessible for the transformer environment. So, to make a
`foo' binding that has a runtime value and a syntax-time value, you
produce syntax that defines some `hidden-foo' as the actual run-time
expression, then create a macro procedure that always expands to
`hidden-foo', wrap that in the applicable struct type and hang the
syntactic information there.
I used this approach in my course plugin (if you want to see the code,
get it from csu660.barzilay.org/csu660.plt), which is a good sample of
what you can do with this:
(define-type EXPR
[Num (n number?)]
[Add (l EXPR?) (r EXPR?)]
[Sub (l EXPR?) (r EXPR?)])
(define (eval expr)
(cases expr
[(Num n) n]
[(Add l r) (+ (eval l) (eval r))]))
Note that unlike the EoPL language, `cases' does not require the type
identifier. Instead, the `define-type' defines `Num' and `Add' as
above -- they can be used as a runtime value (constructor procedures),
and they can be used at syntax-time which is how `cases' knows what
type is expected there (so it can complain about a missing case).
[I think that Dave Herman came up with the same idea and put it in a
planet library.]
On Oct 29, Sam Tobin-Hochstadt wrote:
> What you probably want here is a `module-identifier-mapping', which is a
> hashtable keyed on identifiers, with the equality being
> `module-identifier=?'. The transformer for `f' can add `id' to the map,
> and then `g' can recognize id by looking it up in the map.
>
> The following code demonstrates the idea:
>
> (module m mzscheme
> (require-for-syntax (lib "boundmap.ss" "syntax"))
> (define-for-syntax mapping (make-module-identifier-mapping))
>
> (provide f g)
>
> (define-syntax (f stx)
> (syntax-case stx ()
> [(f id args ...)
> (begin
> (module-identifier-mapping-put! mapping #'id #'(args ...))
> #'(void))]))
>
> (define-syntax (g stx)
> (syntax-case stx ()
> [(g id)
> (module-identifier-mapping-get mapping #'id)])))
>
> (module n mzscheme
> (require m)
>
> (f one + 3 4)
> (f two * 9 10)
>
> (display (g one))
> (newline)
> (display (g two)))
--
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
http://www.barzilay.org/ Maze is Life!