Why does this Template Haskell work?

Consider this code:

magic :: String -> Q Exp
magic s = [e| putStrLn s |]

Now, as best as I can tell, this shouldn't actually work. Inside the Oxford brackets, s is not in scope. And yet, the above apparently works perfectly.

If we change this example slightly, it now breaks horribly:

magic :: Exp -> Q Exp
magic (VarE n) = [e| putStrLn (nameBase n) |]

Just like before, we have a variable not in scope. And this time, it breaks. But it doesn't complain about a variable not in scope; instead it whines about some undocumented class lacking an instance.

Anyone know what the heck is going on?


s is in scope inside the Oxford brackets. Basically, you're allowed to use values of several types — those with Lift instances — inside the quoted expression, and they'll automatically be turned into the appropriate code to recreate the corresponding value on the other end.

For example, the Lift instance for Integer s simply constructs the corresponding integer literal, while the instance for Maybe simply constructs the appropriate constructor applications. You can even define your own instances of Lift .

You're getting a "no instance" error because n is a Name , which isn't Lift able.


I think the short answer is that the magic function is expected to work as the quotation brackets do capture their local variables (in a way). Essentially, compile-time local variables in quotation brackets get replaced with their literal values and become run-time constants. This is achieved by calling the lift function implicitly, so that [| .. var .. |] becomes [| $(lift var) |].

Perhaps you are confusing this behavior with the fact that they capture local variables uniquely, such that repeated calls of the same quotation will not interfere with one another's variable names. This is is achieved through calls to newName behind the scenes, which ensures unique variable names.

If it helps, I personally think of the quotation brackets as "splice generators" - little fragments of Haskell code that will be converted to an AST at compilation time and will therefore become splices ready to be inserted wherever. As pointed out by Bulat's tutorials (links from), they act like a form of macro pre-processor, as they are mixtures of Haskell functions generating code and simple automated conversion of haskell code to TH AST.

Edit: Seems ehird beat me to the answer - I am leaving my answer around, in case it provides some additional value.

链接地址: http://www.djcxy.com/p/5674.html

上一篇: 具有约束的专业化

下一篇: 为什么这个模板Haskell工作?