{-| Module : Data.Derive.TopDown Description : Help Haskellers derive class instances for composited data types. Copyright : (c) songzh License : BSD3 Maintainer : Haskell.Zhang.Song@hotmail.com Stability : experimental Class dependencies can be complex sometimes, such as numeric and monadic classes. Making instances of them can be very tedious. Functoins in this module will help you derive the specified class instance with all the superclass instances of it. For using this module, you may need to enable the following langauge extensions: @TemplateHaskell@, @StandaloneDeriving@, @DeriveGeneric@, @DeriveDataTypeable@, @GeneralizedNewtypeDeriving@, @DeriveAnyClass@ You may also need to enable GHC options @-ddump-splices@. For example: > data A = A > deriving_superclasses ''Ord ''A You wil get: > deriving_superclasses ''Ord ''A > ======> > deriving instance Ord A > deriving instance Eq A 'Eq' is automatically derived when 'Ord' is derived, since 'Eq' is a superclass of 'Ord' > newtype IO_ a = IO_ (IO a) > strategy_deriving_superclasses newtype_ ''MonadIO ''IO_ You will get: > strategy_deriving_superclasses newtype_ ''MonadIO ''IO_ > ======> > deriving newtype instance MonadIO IO_ > deriving newtype instance Monad IO_ > deriving newtype instance Applicative IO_ > deriving newtype instance Functor IO_ Appearently, @Functor f => Applicative f => Monad f => MonadIO f@ > newtype F32 = F32 Float > newtype_deriving_superclasses ''RealFloat ''F32 You will get: > newtype_deriving_superclasses ''RealFloat ''F32 > ======> > deriving newtype instance RealFloat F32 > deriving newtype instance RealFrac F32 > deriving newtype instance Real F32 > deriving newtype instance Num F32 > deriving newtype instance Ord F32 > deriving newtype instance Eq F32 > deriving newtype instance Fractional F32 > deriving newtype instance Floating F32 Some of these examples are from [#13668](https://ghc.haskell.org/trac/ghc/ticket/13668). -} module Data.Derive.Superclass (deriving_superclasses, #if __GLASGOW_HASKELL__ >= 802 strategy_deriving_superclasses, newtype_deriving_superclasses, gnds #endif )where import Data.Derive.TopDown.Lib import Language.Haskell.TH import Language.Haskell.TH.Lib import Debug.Trace import Control.Monad import Data.List import Control.Monad.Trans.State import Control.Monad.Trans import Data.Maybe import Language.Haskell.TH.Ppr isHigherOrderClass :: Name -> Q Bool isHigherOrderClass ty = do cla <- reify ty case cla of ClassI (ClassD _ _ vars _ _) _ -> do let (KindedTV _ k) = head vars if k == StarT then return True else return False _ -> error $ show ty ++ " is not a class" deriving_superclasses :: Name -> Name -> Q [Dec] deriving_superclasses cn tn = do a <- evalStateT (deriving_superclasses' Nothing cn tn) [] return a #if __GLASGOW_HASKELL__ >= 802 strategy_deriving_superclasses :: DerivStrategy -> Name -> Name -> Q [Dec] strategy_deriving_superclasses st cn tn = do a <- evalStateT (deriving_superclasses' (Just st) cn tn) [] return a -- |Use newtype strategy to derive all the superclass instances. newtype_deriving_superclasses = strategy_deriving_superclasses NewtypeStrategy -- |Abbreviation for @newtype_deriving_superclasses@. gnds = newtype_deriving_superclasses #endif #if __GLASGOW_HASKELL__ >= 802 deriving_superclasses' :: Maybe DerivStrategy -> Name -> Name -> StateT [Type] Q [Dec] deriving_superclasses' st cn tn = do #else deriving_superclasses' :: Name -> Name -> StateT [Type] Q [Dec] deriving_superclasses' cn tn = do #endif (tvbs,cons) <- getTyVarCons cn tn let tp = AppT (ConT cn) (ConT tn) types <- get isCnHighOrderClass <- lift $ isHigherOrderClass cn classContext <- if isCnHighOrderClass then lift $ generateClassContext cn tn else return Nothing -- let Just a = classContext let typeNames = map getTVBName tvbs isIns <- lift $ isInstance' cn [ConT tn] let context = maybeToList classContext if (isIns || elem tp types) then return [] else do topClassInstance <- return [StandaloneDerivD #if __GLASGOW_HASKELL__ >= 802 st #endif context tp] modify (tp:) ci <- lift $ reify cn case ci of ClassI (ClassD ctx _ _ _ _) _ -> do let classConTs = map getTypeConstructor ctx ss <- fmap (nub.concat) $ forM classConTs $ \(ConT className) -> do superclass_decls <- deriving_superclasses' #if __GLASGOW_HASKELL__ >= 802 st #endif className tn return superclass_decls return $ topClassInstance ++ ss