[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