Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to "apply" a type-variable in Template Haskell?

I'm passing a record with the following structure to a Template Haskell function:

module Editor.App where

data WithMaybe
data WithoutMaybe

type family TypeSelector a b where
  TypeSelector WithMaybe b = Maybe b
  TypeSelector WithoutMaybe b = b

data MyRecord a = MyRecord
  { field1 :: TypeSelector a Int
  , field2 :: TypeSelector a String
  }

$(myTHFunction ''MyRecord)

Inside myTHFunction I'm calling reify and it is correctly giving me the following type-Info:

TyConI 
  (DataD 
    []
    Editor.App.MyRecord 
    [KindedTV a_6989586621679348600 StarT] 
    Nothing 
    [RecC Editor.App.MyRecord 
      [ ( Editor.App.field1
        , Bang NoSourceUnpackedness NoSourceStrictness
        , AppT  (AppT (ConT Editor.App.TypeSelector) (VarT a_6989586621679348600)) 
                (ConT GHC.Types.Int) )
      , ( Editor.App.field2
        , Bang NoSourceUnpackedness NoSourceStrictness
        , AppT  (AppT (ConT Editor.App.TypeSelector) (VarT a_6989586621679348600)) 
                (ConT GHC.Base.String) )
      ]
    ] 
    []
  )

However, in my application logic, I cannot proceed with an unapplied KindedTV a_6989586621679348600 StarT. So, my question is:

  • how do I "apply" this type-variable in TH
  • or, how do I apply it before passing it to TH. I tried $(myTHFunction ''(MyRecord SomeSelector)) but that doesn't work.
like image 655
Saurabh Nanda Avatar asked Apr 19 '26 10:04

Saurabh Nanda


1 Answers

This seems like possibly two questions:

  1. You want to know how to substitute a free type variable in a type.

    The best way to do this I know of is to use applySubstitution from the th-abstraction package, which also helpfully includes normalized representations of datatypes across GHC versions so you don’t tether yourself to a single version of Template Haskell.

  2. You want to know how to pass an applied type using TH instead of a single name.

    The quoted syntax—i.e. 'ValueName or ''TypeName—quote names, which correspond simply to references to bindings. MyRecord SomeSelector clearly isn’t a name, it’s a type. Therefore, you should use the type quotation syntax instead of the name quotation syntax, which is written [t|MyRecord SomeSelector|]. This quotation will give you a value of type Language.Haskell.TH.Syntax.Type, which is a structured datatype that represents the AST of an arbitrary Haskell type.

As far as I know, there is no function written down in some library that allows you to go directly from a Type with the shape T X ... to the reified list of constructors associated with T, with its argument variables instantiated with types X .... This is, of course, a partial function: [t|forall a. a|] quotes a valid Type, but it is not of the shape T X ..., so you’ll have to handle that failure mode yourself (and hopefully report a useful error message). It can be defined in terms of applySubstitution without too much effort, but you will have to do a bit of groveling through the Type you receive to extract the right information.

like image 69
Alexis King Avatar answered Apr 22 '26 00:04

Alexis King



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!