Transformative type families

I wished Haskell as nice macro system (i.e. without IO or stage restriction) but it doesn’t seem that there is an appetite for it. So I was reading (for the nth time) about generic and I was wandering if it would make sense and be useful to be able use type families to deconstruct and transform type ala Generic.

Type families can be seen as a function taking a type and returning a new one, so why not allow them transform the type. It could be used to create a HKD from a plain record, merge to records etc …

For example one could write (using Generic class)

type family F f a where
    F f (a :+: b) = F f a :+: F f b
    F f (a :*: b) = F f a :*: F f b
    F f a = f a

Would that be of any use, or is there already a way to do so (or something else better in the pipeline achieving the same goal )?

Do you mean so that if the user writes data P a b = MkP a b then F f (P a b) is isomorphic to P (f a) (f b)?

1 Like

That’s not why I meant but yes. What I meant was if the user writes data P = MkP a b then F f P is isomorphic to PF = MkP' (f a) (f b).

Indeed, we have it already, or maybe half of it.
It seems that HKD is using a type family on Rep

-- | Calculate the "partial representation" of a type.
type HKD_ (f :: Type -> Type) (structure :: Type)
  = GHKD_ f (Rep structure)

-- | Calculate the "partial representation" of a generic rep.
type family GHKD_ (f :: Type -> Type) (rep :: Type -> Type)
    = (output :: Type -> Type) | output -> f rep where
  GHKD_ f (M1 index meta inner) = M1 index meta (GHKD_ f inner)
  GHKD_ f (left :*: right)      = GHKD_ f left :*: GHKD_ f right
  GHKD_ f (K1 index value)      = K1 index (f value)
  GHKD_ f (left :+: right)      = GHKD_ f left :+: GHKD_ f right

Which is really clever. If I am correct then the resulting type of HKD is not vanilla type but of the Generic genre (a mix of M1 and :*: etc …). So you don’t have a nice plain record with field accessor
(this i why I guess HKD as to use label to acces fields) and I’m not sure if you can do pattern matching.
To transform fully a type we would need the opposite of Rep, something which create a plain type from it’s generic representation (unless it already exists somewhere).

Correct

To transform fully a type we would need the opposite of Rep, something which create a plain type from it’s generic representation

Yeah I think the only thing that allows you to define types is TH.

1 Like

Type families are still relatively new to GHC and their compilation times are still excessive. I’m looking forward to the progress being made toward Dependent Haskell to alleviate some of that friction, but for the moment there are severe slowdowns when using type families liberally, to the extent that it’s still worth finding a solution in value-land.