Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to capture type variable in TemplateHaskell quote

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
like image 325
dcastro Avatar asked Dec 09 '25 01:12

dcastro


1 Answers

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.

like image 70
Li-yao Xia Avatar answered Dec 11 '25 20:12

Li-yao Xia



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!