[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