{-# LANGUAGE TemplateHaskell #-} -- | Generate 'Syntactic' instances for tuples module Language.Syntactic.Functional.Tuple.TH ( deriveSyntacticForTuples ) where import Language.Haskell.TH import Data.NestTuple import Data.NestTuple.TH import Language.Syntactic ((:<:), Syntactic (..)) import Language.Syntactic.TH -- Make instances of the form -- -- > instance -- > ( Syntactic a -- > , ... -- > , Syntactic x -- > -- > , internalPred (Internal a) -- > , ... -- > , internalPred (Internal x) -- > -- > , Tuple :<: sym -- > , Domain a ~ mkDomain sym -- > -- > , Domain a ~ Domain b -- > , ... -- > , Domain a ~ Domain x -- > , extraConstraint -- > ) => -- > Syntactic (a,...,x) -- > where -- > type Domain (a,...,x) = Domain a -- > type Internal (a,...,x) = (Internal a ... Internal x) -- nested pairs -- > desugar = desugar . nestTup -- use pair instance -- > sugar = unnestTup . sugar -- use pair instance -- -- Instances will be generated for width 3 and upwards. The existence of an -- instance for pairs is assumed. deriveSyntacticForTuples :: (Type -> Cxt) -- ^ @internalPred@ (see above) -> (Type -> Type) -- ^ @mkDomain@ (see above) -> Cxt -- ^ @extraConstraint@ (see above) -> Int -- ^ Max tuple width -> DecsQ deriveSyntacticForTuples internalPred mkDomain extraConstraint n = return $ map deriveSyntacticForTuple [3..n] where deriveSyntacticForTuple w = instD ( concat [ map (classPred ''Syntactic ConT . return) varsT , concatMap internalPred $ map (AppT (ConT ''Internal)) varsT , [classPred ''(:<:) ConT [ConT (mkName "Tuple"), VarT (mkName "sym")]] , [eqPred domainA (mkDomain (VarT (mkName "sym")))] , [eqPred domainA (AppT (ConT ''Domain) b) | b <- tail varsT ] , extraConstraint ] ) (AppT (ConT ''Syntactic) tupT) [ tySynInst ''Domain [tupT] domainA , tySynInst ''Internal [tupT] tupTI , FunD 'desugar [ Clause [] (NormalB (foldl AppE (VarE '(.)) $ map VarE [mkName "desugar", 'nest])) [] ] , FunD 'sugar [ Clause [] (NormalB (foldl AppE (VarE '(.)) $ map VarE ['unnest, mkName "sugar"])) [] ] ] where varsT = map VarT $ take w varSupply tupT = foldl AppT (TupleT w) varsT tupTI = foldNest id mkPairT $ toNest $ map (AppT (ConT ''Internal)) varsT domainA = AppT (ConT ''Domain) (VarT (mkName "a"))