RE: [Template-haskell] Hygienic macros and lexical-scoping
| > | 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
participants (1)
-
Simon Peyton-Jones