[Template-haskell] Hygienic macros and lexical-scoping

Kamil Skalski nazgul at omega.pl
Wed Feb 25 00:33:58 EST 2004


Hello!

I'm developer of meta-programming system in a new language Nemerle. As we are 
coming near to implementation of lexical scoping and alpha-renaming in our 
system, I would like to share some ideas and ask few questions about Haskell 
Templates' approach to these problems.

As I read in 'Template meta-programming in Haskell', the implementation 
translates 
[| \x -> $(f [| x |]) |] 
to 
do { x <- gensym "x"; lam [Pvar x] (app f (var x) }   

(I'm not familiar with Haskell, so I may have mistaken some syntax)

My question is: when binding of variables is resolved? Is it during 
translation of quotation, or maybe during expansion of $(...) where the above 
code is used?
After reading the paper, I'm convinced that it's former case. But let's 
consider:
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.

In our system we are shifting binding of variables from quotation translation 
to macro expansion phase, so [| x |] can be "catched" inside 'using' 
meta-function. Resolving of scoping is done after all executions of macros 
are done. It involves quite complex algorithm to tag variables with place 
where they come from - we are adapting Dybvig's algorithm into our system, so 
we could use most flexible convention introduced by Scheme community.

Assuming I'm not wrong by now, I also have question, was the other option 
considered during design of Template Haskell? 

As we discussed our design, there was some confusion if macros should 
introduce new definitions into program. I noticed, that in Haskell it is done 
by special keyword 'splice', and it's forbidden inside quotations. As we 
decided to resolve names in late phase, we could introduce definitions in 
arbitrary place. Some questions arise in that case:
Let's consider following macros (in Nemerle syntax, as I'm more used to it)

using Foo;   /// it introduces functions 'blah' and 'bar' variables
macro m() { <[ def bar() { 1 } ]> }
macro m'() { <[ m(); blah() + bar() ]> }

does m'() generate  
def bar_43 = 1; Foo.blah() + Foo.bar()
or
def bar_43 () { 1 }; Foo.blah() + bar_43()

lexical scoping should theoretically mean the former case, but if we consider 
function MacroUseSymbol (x : string) - that generates symbol, which will 
behave as one introduced in macro use site, then latter case is valid.

The same function might be used to implement 'using' macro, I've mentioned:

macro using (x : string, val, body) {
def x = MacroUseSymbol (x);
<[ def $(x : var) = $val;
    $body;
    $(x : var).Dispose ()
]>
}

My last question is if this approach was considered and what are opinions 
about introducing this kind of lexial scoping into languages with explicit 
quoasi-quotations.

I can describe our algorithm if anyone is interested (as it is still under 
discussions).

Kamil Skalski
Nemerle developer - http://nemerle.org



More information about the template-haskell mailing list