With lift, the expression is evaluated, then the result '1' is lifted into an AST. But TH quotes do something entirely different: they lift *the expression* into an AST. In order to do so, the quoting mechanism needs to parse its input string, then determine what each identifier is referring to.
> > let p :: (Show a, Lift a) => a -> ExpQ; p n = [| show n |]
The quote has two terms: show and n. 'n' is a lambda-bound value, and show is free. Free variables are looked up in the environment. That's why we see 'VarE GHC.Show.show' in the AST above; the fully-qualified Name is generated and the AST references that name. (numeric and string literals are represented directly)
This is the key difference between this function definition and running the splice above: in the function 'n' is lambda-bound, whereas in the above splice 'x' is a free variable.
Lambda bindings can't be referenced by name because that name may not be in scope when the generated splice is run. Instead, lambda-bound values must be lifted directly into the AST, which is exactly what 'lift' does. If we apply the function to a value, we can see the generated AST:
AppE (VarE GHC.Show.show) (LitE (IntegerL 2))
The generated AST has the number 2, and applies the function GHC.Show.show to it.
If we want to show something that doesn't have a Lift instance, we can't do it directly. However, we can do this:
> > let q :: Show a => a -> ExpQ; q n = [| $(lift $ show n) |]
> > runQ (q 2)
> ListE [LitE (CharL '2')]
Note the differences. We no longer require that 'n' has a Lift instance. However, the actual value of 'n' never appears in the AST! Instead, we first show 'n', then lift in the resulting string. The order of operations is changed too. In the first case, the literal 2 is lifted into the AST via lift, and the generated splice will apply show to that number whenever the splice is run. In the second case, (show 2) is evaluated first, then the result is lifted into the AST (again via lift), causing that string to be referenced within the splice.
HTH,
John