
On Mon, Jul 1, 2013 at 6:01 AM, TP
oleg@okmij.org wrote:
pr :: Name -> ExpQ pr n = [| putStrLn $ (nameBase n) ++ " = " ++ show $(varE n) |]
The example is indeed problematic. Let's consider a simpler one:
foo :: Int -> ExpQ foo n = [|n + 1|]
The function f, when applied to an Int (some bit pattern in a machine register), produces _code_. It helps to think of the code as a text string with the source code. That text string cannot include the binary value that is n. That binary value has to be converted to the numeric text string, and inserted in the code. That conversion is called `lifting' (or quoting). The function foo is accepted because Int is a liftable type, the instance of Lift. And Name isn't.
Thanks Oleg, Probably the following question will be stupid, but I ask it anyway: in my initial example, (nameBase n) returns a String, so we are not in the case where it is not "liftable"? In fact I am not sure to have understood your answer.
The problem isn't the output of nameBase, it's the input parameter 'n'. In your example, you've created a function that takes input (a Name) and generates code based upon that input. In order to lift a value (n) from an ordinary context into a quote, it needs a Lift instance.
Now, I have found another behavior difficult to understand for me:
runQ $ lift "u" ListE [LitE (CharL 'u') runQ $ [| "u" |] LitE (StringL "u")
So we have similar behaviors for lift and [||]. We can check it in a splice:
$( [| "u" |] ) "u" $( lift "u" ) "u"
But if I replace a working version:
pr n = [| putStrLn ( $(lift( nameBase n ++ " = " )) ++ show $(varE n) ) |]
by
pr n = [| putStrLn ( $([| (nameBase n) ++ " = " |]) ++ show $(varE n) ) |]
I again get the error
In the working version, 'n' appears inside a splice, whereas in the other n is in a quote. AFAIK any value can be used in a splice (provided it meets the staging restrictions), whereas only Lift-able values can be used in a quote. Perhaps it helps if you think about what a quote does: it allows you to write essentially a string of Haskell code that is converted into an AST. For this to work, the quote parser needs to know how to generate the AST for an identifier. Like much of Haskell, it's type-driven. For identifiers in scope from imports, TH simply generates a variable with the correct name. But for data, the parser needs a way to generate an AST representation, which is what Lift is for.