[Template-haskell] Hygienic macros and lexical-scoping

Simon Peyton-Jones simonpj at microsoft.com
Thu Feb 26 12:56:24 EST 2004


| > | 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')

Ah.  I thought 'using' was a keyword!  OK, so it's like this:

  foo :: String -> Q Exp -> Q Exp -> Q Exp
  foo x val body = [| do { $(mkName x) <- $val; $body; dispose $(dyn x)
} |]

Here, 	mkName :: String -> Name

	dyn :: String -> Q Exp
	dyn s = return (Var (mkName s))

and I'm assuming an as-yet-unimplemented feature of TH which lets you
splice a Name into a binding position (thus ($n <- ...)  or (\$n ->
...)).



The binding $(mkName x) certainly captures the occurrence $(dyn x).  But
you also want to capture some occurrences of 'x' in 'body'.   Thus,
consider

	foo "wug" [| 77 |]  [| wug > 2 |] 

does the 'wug' in 'wug > 2' get captured by the (mkName "wug") binding?
No, not in TH.  The above call is statically rejected unless wug is
already in scope.  For example
	let wug = 88 in 
	foo "wug" [| 77 |]  [| wug > 2 |]

And in this case, the 'wug > 2' is indissoubly bound to the 'wug = 88'
binding.  

What if you *want* the 'wug > 2' to be bound un-hygienically to the
(mkName "wug") binding?  Then use 'dyn' thus

	let wug = 88 in 
	foo "wug" [| 77 |]  [| $(dyn "wug") > 2 |]

Now, plainly, the wug=88 binding plays no role.

| 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.

I hope the above makes it clear that you can express either behaviour in
TH.

To be sure, the references to dynamically scoped things are
inconvenient, as we see in $(dyn "wug") > 2, but at least there's a
simple story to tell.

| see, before any expansion. Nevertheless we will try another approach
and
| experiment with such system.

Indeed -- this is a rather complex design space, so it's great to
explore new parts of it.

Simon



More information about the template-haskell mailing list