[Template-haskell] Hygienic macros and lexical-scoping
Kamil Skalski
nazgul at omega.pl
Wed Feb 25 21:34:43 EST 2004
Thank you for your response and clarifying things, Simon.
> | using x val body = [| do { (var x) <- val; body; (var x).Dispose () }
> |]
> | // x is of type string
> |
> | [| \y -> do { $(using "x" [| x |]); f y |]
> |
> | wouldn't work, and one would have to use gensym by his own to get
>
> expected
>
> | sematics.
>
> I'm sorry, I didn't understand this at all. What is 'using x val body'?
> What is .Dispose()? Not Template Haskell certainly.
Well, it supposed to be a function, which takes 'x' (of type string), 'val'
and 'body' (being expressions) and creates code which does:
- define local variable of name 'x' initialized with 'val'
- execute 'body' (it is assumed to have occurrences of 'x' inside, which
should be captured by local 'x'
- disposes 'x' (it has method 'Dispose', so I think its Haskell counterpart
would be calling function 'Dispose' on 'x')
This can be implemented in TH with (dyn "x") which you mentioned, but if
'body' is itself passed from another context and 'x' is introduced in
f body = [| using "x" Foo $( [| do { dosomething x; body } |] ) |]
then some external 'x' in original 'body' might get catched by dynamic
binding, which is not hygienic behavior.
I'm aware that this can be workaround with manually creating 'x' with newName
and using this Name. Our decision to bind variables after macros expansion
makes it possible to handle such cases in other way. There are opposite
design goals, and I clearly see advantage of TH's one - bind to what you can
see, before any expansion. Nevertheless we will try another approach and
experiment with such system.
To make myself more clear, I will give another example. Unfortunately I'm not
able to easily write Haskell counterpart, so I will try to describe what I
mean in syntax of our system. (It's more similar to C# / Ocaml, where
meta-functions are tagged explicitly at definition, but used like ordinary
functions. Quotations are constructing code <[ e_1; e_2; ... ]>, while $
splices value of meta-expressions into enclosing quoted code).
We have a following macro
macro @for (init, cond, change, body) {
<[
$init;
def loop () : void {
when ($cond) { $body; $change; loop() }
};
loop ();
]>
}
It can be used e.g.
for (mutable i <- 0; i < 10; i <- i + 1, printf ("%d\n", i))
If we put it into quotation
<[ for (mutable i <- 0; i < 10; i <- i + 1) printf ("%d\n", i) ]>
we would not find bindings for 'i' - definition of local 'i' is just parameter
of function call, so other parameters are not in its scope and compilation of
this quotation would fail. It's quite inconsistent with writing 'for' in
plain code, where binding is done after its expansion. This and other
examples made us consider binding always after expansion and handling hygiene
in other way. This also shifts some error messages to next compilation stage,
as you describe in notes.
> As I say above, TH supports both pre-expansion binding (via plain
> mentions of a variable), and post-expansion biding (via "dyn"). Whatever
> you choose to do, let me encourage you to give it a formal description.
This needs good documentation for sure, as there are many contradictory
intuitions at field of names binding. We are trying to design system as easy
to use and understand as possible.
One again thanks for pointing me revised notes and arguments behind your
design. It was quite useful to see more examples and problems that can
araise.
Kamil Skalski
Nemerle developer - http://nemerle.org
More information about the template-haskell
mailing list