module Data.Tuple.Morph.TH (
sizeLimit,
mkRep,
mkHFoldableInst,
mkHUnfoldableInst
) where
import Control.Monad
import Data.Proxy
import Data.Tuple.Morph.Append
import Data.Type.Equality
import Language.Haskell.TH
mkNames :: Int -> [Name]
mkNames n = take n $ map mkName $ [1 ..] >>= flip replicateM ['a' .. 'z']
tupleFrom :: [Type] -> Type
tupleFrom vars = foldl AppT (TupleT (length vars)) vars
sizeLimit :: Int
sizeLimit = 13
mkRep :: Int -> Q [Dec]
mkRep n = fmap (:[])
$ closedTypeFamilyKindD (mkName "Rep")
[(PlainTV (mkName "tuple"))] (AppT ListT StarT)
$ map mkEqn [n, n1 .. 2] ++ map return
[ TySynEqn [TupleT 0] PromotedNilT
, TySynEqn [a] (AppT (AppT PromotedConsT a) PromotedNilT)
]
where
a = VarT (mkName "a")
repName = mkName "Rep"
append = VarT ''(++)
mkEqn k = do
let names = mkNames k
vars = map VarT names
tuple = tupleFrom vars
reps = map (AppT (ConT repName)) vars
rep = foldr1 (\x y -> AppT (AppT append x) y) reps
return $ TySynEqn [tuple] rep
mkInst :: Name -> Int -> ([Name] -> [Dec]) -> Dec
mkInst className k decs =
let names = mkNames k
tvars = map VarT names
in InstanceD [ClassP className [tvar] | tvar <- tvars]
(AppT (ConT className) (tupleFrom tvars))
(decs names)
mkHFoldableInst :: Int -> Q Dec
mkHFoldableInst k = return $ mkInst (mkName "HFoldable") k $ \names ->
let toHListName = mkName "toHList"
tupleP = TupP $ map VarP names
hlists = map (\n -> AppE (VarE toHListName) (VarE n)) names
body = NormalB $ foldr1 (\x y -> AppE (AppE (VarE '(++@)) x) y) hlists
toHList = FunD toHListName [Clause [tupleP] body []]
in [toHList]
mkHUnfoldableInst :: Int -> Q Dec
mkHUnfoldableInst k = return $ mkInst (mkName "HUnfoldable") k $ \names ->
let hListParserName = mkName "hListParser"
repName = mkName "Rep"
bindMIName = mkName "bindMI"
returnMIName = mkName "returnMI"
proxy = SigE (ConE 'Proxy)
(AppT (ConT ''Proxy)
(AppT (ConT repName)
(VarT $ last names)))
theorem = AppE (VarE 'appendRightId) proxy
bindE n e = AppE (AppE (VarE bindMIName)
(VarE hListParserName))
(LamE [VarP n] e)
returnE = (AppE (VarE returnMIName) (TupE (map VarE names)))
matchBody = NormalB $ foldr bindE returnE names
body = NormalB $ CaseE theorem [Match (ConP 'Refl []) matchBody []]
hListParser = FunD hListParserName [Clause [] body []]
in [hListParser]