Normalize type family instance within Template Haskell splice
Asked Answered
M

0

7

I'm using the genifunctors package to generate a functor instance for a type whose definition involves type families.

The first module defines the data type itself:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
module Temp where

data Record (p :: (*,*))

type family Fst p where Fst (Record '(a,b)) = a
type family Snd p where Snd (Record '(a,b)) = b

data Bar s = Bar {
  field_a :: Fst s,
  field_b :: Snd s
}

newtype Baz a = Baz { getBaz :: Bar (Record '(Maybe a, [a])) }

This works just as expected:

λ> import Temp 
λ> :t Baz $ Bar (Just "a") ["b"] 
Baz $ Bar (Just "a") ["b"] :: Baz [Char]

The Functor instance is defined in a separate module:

{-# LANGUAGE TemplateHaskell #-}
module Temp2 where

import Temp

import Data.Generics.Genifunctors

instance Functor (Baz a) where
  fmap = $(genFmap ''Baz)

And gives this error:

λ> import Temp1
src/Temp2.hs:9:12-24: Exception when trying to run compile-time code: …
  unexpected TyCon: FamilyI (ClosedTypeFamilyD Temp.Fst [PlainTV p_1627394000] (Just StarT) [TySynEqn [AppT (ConT Temp.Record) (AppT (AppT (ConT GHC.Tuple.(,)) (VarT a_1627394001)) (VarT b_1627394002))] (VarT a_1627394001)]) []
Code: genFmap ''Baz
In the splice: $(genFmap ''Baz)

This happens because genifunctors, just like geniplate, can only handle type constructors from newtype or data declarations.

This could be fixed by normalizing the type before recursively inspecting it.

So, is there a way to do so within a Template Haskell splice? (i.e. within the Q monad?)

Minoru answered 26/9, 2014 at 13:24 Comment(2)
The function genFmap is using reify in order to get information about Baz. You are not passing it a representation of the type, so you can't "normalize the type" before passing it to genFmap. So you would have to modify the source of the package. You can write your own program which will manipulate the Type AST in order to remove trivial applications of type families ("normalize"), but TH will not do it automatically (of course this is non-trivial problem in general).Clientage
@Clientage can you turn your comment into an answer, since it seems to answer the question?Pyrogallate

© 2022 - 2024 — McMap. All rights reserved.