RE: Hygienic macros and lexical-scoping

"Simon Peyton-Jones" <[email protected]>
Newsgroups gmane.comp.lang.haskell.template
Message-ID <4B93206CA3C55D4F96A61C9B1DC80DE3DF3710@EUR-MSG-03.europe.corp.microsoft.com>
| > | 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.