{-# LANGUAGE TemplateHaskell #-} module Data.Constructors.TH (EqC(..),deriveEqC) where import Data.Constructors.EqC import Language.Haskell.TH as TH import Language.Haskell.TH.Syntax as TH -- | Derive an instance of @EqC@ for any simple type -- For example, @deriveEqC ''Either@ will generate: -- -- > instance EqC (Either a b) where -- > eqConstr Left{} Left{} = True -- > eqConstr Right{} Right{} = True -- > eqConstr _ _ = False deriveEqC :: Name -> DecsQ deriveEqC n = do (saturatedType,constructors) <- extractTypeCons n return $ [InstanceD Nothing [] (AppT (ConT ''EqC) saturatedType) [FunD 'eqConstr constructors]] extractTypeCons :: Name -> Q (TH.Type,[Clause]) extractTypeCons n = do true <- lift True false <- lift False reify n <&> \case TyConI (DataD _ _ tyVars _ cons _) -> (foldl (\c -> AppT c . extractTV) (ConT n) tyVars ,foldr (\c acc -> Clause [RecP c [], RecP c []] (NormalB true) [] : acc) [Clause [WildP,WildP] (NormalB false) []] (map (\(NormalC n' _) -> n') cons)) _ -> error "invalid name" extractTV :: TyVarBndr -> TH.Type extractTV = \case PlainTV n -> VarT n KindedTV n _ -> VarT n (<&>) :: Functor f => f a -> (a -> b) -> f b (<&>) = flip (<$>)