Reputation: 68640
I'm trying to write a Lift instance that lifts not only the constructor, but also its type variables.
For example, take Proxy a
. I need a Lift
instance such that, when lift (Proxy @Int)
is spliced, GHC will correctly infer than the generated expression is a Proxy Int
.
-- GHC should infer that x :: Proxy Int
x = $(TH.lift (Proxy @Int))
I tried this:
instance Lift (Proxy a) where
lift _ = [|Proxy @a|]
x = $(TH.lift (Proxy @Int))
It seems TH captured a
and not Int
as expected.
I'm not sure what else to try
/.../TH/Test.hs:15:7: error:
• The exact Name ‘a’ is not in scope
Probable cause: you used a unique Template Haskell name (NameU),
perhaps via newName, but did not bind it
If that's it, then -ddump-splices might be useful
Upvotes: 3
Views: 358
Reputation: 33389
template-haskell doesn't seem to provide anything like that. But there might be a solution that you can implement from scratch. The idea is to define a class to carry a quote representing each type:
class TLift a where
tlift :: Q Type
For instance:
instance TLift Int where
tlift = [t|Int|]
-- and so on
Then to define a quote featuring a type application:
proxyQ :: forall a. TLift a => Q Exp
proxyQ = [|Proxy @( $(tlift @a) )|]
One limitation here is that TLift
instances can only produce quotes for completely concrete types, no type variables. Maybe reflection can work around that.
Upvotes: 2
Reputation: 27003
I'm pretty sure this can't be done with a direct reference to the type in order to use type applications. By the time the spliced code makes a reference to a
, the scope in which it was defined no longer exists.
But I believe this is one of the known issues that led to the creation of typed template Haskell. And that can be used to solve this. Note that GHC 8.10 introduced an additional entry in the class, liftTyped
, which can solve this directly. But it also provides the hint needed to use this on earlier versions of GHC, which is that lift x === unTypeQ (liftTyped x)
.
From that, I could see how to write an instance of Lift
for Proxy a
for versions of GHC older than 8.10.
instance Lift (Proxy a) where
lift x = unTypeQ (helper x)
where
helper :: Proxy b -> Q (TExp (Proxy b))
helper _ = [|| Proxy ||]
For GHC 8.10, this would just be
instance Lift (Proxy a) where
liftTyped _ = [|| Proxy ||]
Honestly, there are a bunch of Lift
instances seemingly missing. This is just one of the more indirect ones to write, at least before GHC 8.10.
Upvotes: 0