I need to put a function into Template Haskell code. I am using the expression syntax:
[|f|]Some functions seem to work automa开发者_运维百科tically. However, for this particular one I get the following erroe message:
No instance for (Lift (String -> [Content]))
I have no idea how to make a lift instance for a function, and can't seem to find any useful information. Can anyone point me to a resource or give me an idea of how this is accomplished in general? In the mean time I will see if I can pare down my specific example.
I'll take a stab, though TH can be hard to debug without seeing more code.
Let's take a look at some sample code:
foo.hs:
{-# Language TemplateHaskell #-}
baz x = let f y = x + y
in [| f |]
bez x = let f y = x + y
in [| \y -> f y |]
boz x = [| \y -> x + y |]
g x y = x + y
byz x = [| g x |]
Now we can fire this up in GHCi (I'm on version 7.0.2, which is what ships with the current Haskell Platform):
$ ghci foo.hs -XTemplateHaskell
*Main> :m +Language.Haskell.TH
*Main Language.Haskell.TH> runQ (baz 2)
<interactive>:1:7:
No instance for (Language.Haskell.TH.Syntax.Lift (a0 -> a0))
arising from a use of `baz'
Possible fix:
add an instance declaration for
(Language.Haskell.TH.Syntax.Lift (a0 -> a0))
In the first argument of `runQ', namely `(baz 2)'
In the expression: runQ (baz 2)
In an equation for `it': it = runQ (baz 2)
*Main Language.Haskell.TH> runQ (bez 2)
<interactive>:1:7:
No instance for (Language.Haskell.TH.Syntax.Lift (a0 -> a0))
arising from a use of `bez'
Possible fix:
add an instance declaration for
(Language.Haskell.TH.Syntax.Lift (a0 -> a0))
In the first argument of `runQ', namely `(bez 2)'
In the expression: runQ (bez 2)
In an equation for `it': it = runQ (bez 2)
*Main Language.Haskell.TH> runQ (boz 2)
LamE [VarP y_0] (InfixE (Just (LitE (IntegerL 2))) (VarE GHC.Num.+) (Just (VarE y_0)))
*Main Language.Haskell.TH> runQ (byz 2)
AppE (VarE Main.g) (LitE (IntegerL 2))
What I've done here is attempted to use runQ
to see what the TH splice looks like for each of my functions in the sample code. It fails on baz
and bez
, but works for boz
and byz
.
Looking at the TH for boz
and byz
, we can see how functions are lifted: boz
is basically just referring to +
by name (in VarE GHC.Num.+
), while byz
is just referring to g
by name (in VarE Main.g
).
For baz
and bez
, this option isn't on the table: both of those functions are attempting to splice f
, which is locally bound; hence, reference to VarE f
wouldn't make sense outside of baz
and bez
.
So what's a developer to do? In short, instead of trying [| f |]
, you need to write the expression for f
in the lift directly, in terms of identifiers that will be bound where the splice occurs.
On a side note, it is very easy to write Lift
instances for algebraic data types, since you can always lift globally-defined functions. Here's one for Maybe
:
instance Lift a => Lift (Maybe a) where
lift Nothing = [| Nothing |]
lift (Just a) = [| Just a |]
精彩评论