{-# LANGUAGE CPP #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} module Data.Constraint.Extras.TH (deriveArgDict, deriveArgDictV, gadtIndices) where import Data.Constraint import Data.Constraint.Extras import Data.Maybe import Control.Monad import Language.Haskell.TH deriveArgDict :: Name -> Q [Dec] deriveArgDict :: Name -> Q [Dec] deriveArgDict Name n = do (Type typeHead, [Con] constrs) <- Name -> Q (Type, [Con]) getDeclInfo Name n Name c <- String -> Q Name forall (m :: * -> *). Quote m => String -> m Name newName String "c" [Either Type Type] ts <- Name -> [Con] -> Q [Either Type Type] gadtIndices Name c [Con] constrs let constraints :: [Type] constraints = ((Either Type Type -> Type) -> [Either Type Type] -> [Type]) -> [Either Type Type] -> (Either Type Type -> Type) -> [Type] forall a b c. (a -> b -> c) -> b -> a -> c flip (Either Type Type -> Type) -> [Either Type Type] -> [Type] forall a b. (a -> b) -> [a] -> [b] map [Either Type Type] ts ((Either Type Type -> Type) -> [Type]) -> (Either Type Type -> Type) -> [Type] forall a b. (a -> b) -> a -> b $ \case Left Type t -> Type -> Type -> Type AppT (Type -> Type -> Type AppT (Name -> Type ConT ''Has) (Name -> Type VarT Name c)) Type t Right Type t -> (Type -> Type -> Type AppT (Name -> Type VarT Name c) Type t) [Match] ms <- Name -> [Con] -> Name -> Q [Match] matches Name c [Con] constrs 'argDict [Dec] -> Q [Dec] forall (m :: * -> *) a. Monad m => a -> m a return [ Maybe Overlap -> [Type] -> Type -> [Dec] -> Dec InstanceD Maybe Overlap forall a. Maybe a Nothing [Type] constraints (Type -> Type -> Type AppT (Type -> Type -> Type AppT (Name -> Type ConT ''Has) (Name -> Type VarT Name c)) Type typeHead) [ Pat -> Body -> [Dec] -> Dec ValD (Name -> Pat VarP 'argDict) (Exp -> Body NormalB ([Match] -> Exp LamCaseE [Match] ms)) [] ] ] {-# DEPRECATED deriveArgDictV "Just use 'deriveArgDict'" #-} deriveArgDictV :: Name -> Q [Dec] deriveArgDictV :: Name -> Q [Dec] deriveArgDictV = Name -> Q [Dec] deriveArgDict matches :: Name -> [Con] -> Name -> Q [Match] matches :: Name -> [Con] -> Name -> Q [Match] matches Name c [Con] constrs Name argDictName = do Name x <- String -> Q Name forall (m :: * -> *). Quote m => String -> m Name newName String "x" ([[Match]] -> [Match]) -> Q [[Match]] -> Q [Match] forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap [[Match]] -> [Match] forall (t :: * -> *) a. Foldable t => t [a] -> [a] concat (Q [[Match]] -> Q [Match]) -> ((Con -> Q [Match]) -> Q [[Match]]) -> (Con -> Q [Match]) -> Q [Match] forall b c a. (b -> c) -> (a -> b) -> a -> c . [Con] -> (Con -> Q [Match]) -> Q [[Match]] forall (t :: * -> *) (m :: * -> *) a b. (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b) forM [Con] constrs ((Con -> Q [Match]) -> Q [Match]) -> (Con -> Q [Match]) -> Q [Match] forall a b. (a -> b) -> a -> b $ \case GadtC [Name name] [BangType] _ Type _ -> [Match] -> Q [Match] forall (m :: * -> *) a. Monad m => a -> m a return ([Match] -> Q [Match]) -> [Match] -> Q [Match] forall a b. (a -> b) -> a -> b $ [Pat -> Body -> [Dec] -> Match Match (Name -> [FieldPat] -> Pat RecP Name name []) (Exp -> Body NormalB (Exp -> Body) -> Exp -> Body forall a b. (a -> b) -> a -> b $ Name -> Exp ConE 'Dict) []] ForallC [TyVarBndr Specificity] _ [Type] _ (GadtC [Name name] [BangType] bts (AppT Type _ (VarT Name b))) -> do [Maybe Name] ps <- [BangType] -> (BangType -> Q (Maybe Name)) -> Q [Maybe Name] forall (t :: * -> *) (m :: * -> *) a b. (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b) forM [BangType] bts ((BangType -> Q (Maybe Name)) -> Q [Maybe Name]) -> (BangType -> Q (Maybe Name)) -> Q [Maybe Name] forall a b. (a -> b) -> a -> b $ \case (Bang _, AppT Type t (VarT Name b')) | Name b Name -> Name -> Bool forall a. Eq a => a -> a -> Bool == Name b' -> do Bool hasArgDictInstance <- Bool -> Bool not (Bool -> Bool) -> ([Dec] -> Bool) -> [Dec] -> Bool forall b c a. (b -> c) -> (a -> b) -> a -> c . [Dec] -> Bool forall (t :: * -> *) a. Foldable t => t a -> Bool null ([Dec] -> Bool) -> Q [Dec] -> Q Bool forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> Name -> [Type] -> Q [Dec] reifyInstances ''Has [Name -> Type VarT Name c, Type t] Maybe Name -> Q (Maybe Name) forall (m :: * -> *) a. Monad m => a -> m a return (Maybe Name -> Q (Maybe Name)) -> Maybe Name -> Q (Maybe Name) forall a b. (a -> b) -> a -> b $ if Bool hasArgDictInstance then Name -> Maybe Name forall a. a -> Maybe a Just Name x else Maybe Name forall a. Maybe a Nothing BangType _ -> Maybe Name -> Q (Maybe Name) forall (m :: * -> *) a. Monad m => a -> m a return Maybe Name forall a. Maybe a Nothing [Match] -> Q [Match] forall (m :: * -> *) a. Monad m => a -> m a return ([Match] -> Q [Match]) -> [Match] -> Q [Match] forall a b. (a -> b) -> a -> b $ case [Maybe Name] -> [Name] forall a. [Maybe a] -> [a] catMaybes [Maybe Name] ps of [] -> [Pat -> Body -> [Dec] -> Match Match (Name -> [FieldPat] -> Pat RecP Name name []) (Exp -> Body NormalB (Exp -> Body) -> Exp -> Body forall a b. (a -> b) -> a -> b $ Name -> Exp ConE 'Dict) []] (Name v:[Name] _) -> let patf :: Maybe a -> (Bool -> [Pat]) -> Bool -> [Pat] patf = \Maybe a v' Bool -> [Pat] rest Bool done -> if Bool done then Pat WildP Pat -> [Pat] -> [Pat] forall a. a -> [a] -> [a] : Bool -> [Pat] rest Bool done else case Maybe a v' of Maybe a Nothing -> Pat WildP Pat -> [Pat] -> [Pat] forall a. a -> [a] -> [a] : Bool -> [Pat] rest Bool done Just a _ -> Name -> Pat VarP Name v Pat -> [Pat] -> [Pat] forall a. a -> [a] -> [a] : Bool -> [Pat] rest Bool True pat :: [Pat] pat = (Maybe Name -> (Bool -> [Pat]) -> Bool -> [Pat]) -> (Bool -> [Pat]) -> [Maybe Name] -> Bool -> [Pat] forall (t :: * -> *) a b. Foldable t => (a -> b -> b) -> b -> t a -> b foldr Maybe Name -> (Bool -> [Pat]) -> Bool -> [Pat] forall {a}. Maybe a -> (Bool -> [Pat]) -> Bool -> [Pat] patf ([Pat] -> Bool -> [Pat] forall a b. a -> b -> a const []) [Maybe Name] ps Bool False in [Pat -> Body -> [Dec] -> Match Match (Name -> [Pat] -> Pat conPCompat Name name [Pat] pat) (Exp -> Body NormalB (Exp -> Body) -> Exp -> Body forall a b. (a -> b) -> a -> b $ Exp -> Exp -> Exp AppE (Name -> Exp VarE Name argDictName) (Name -> Exp VarE Name v)) []] ForallC [TyVarBndr Specificity] _ [Type] _ (GadtC [Name name] [BangType] _ Type _) -> [Match] -> Q [Match] forall (m :: * -> *) a. Monad m => a -> m a return ([Match] -> Q [Match]) -> [Match] -> Q [Match] forall a b. (a -> b) -> a -> b $ [Pat -> Body -> [Dec] -> Match Match (Name -> [FieldPat] -> Pat RecP Name name []) (Exp -> Body NormalB (Exp -> Body) -> Exp -> Body forall a b. (a -> b) -> a -> b $ Name -> Exp ConE 'Dict) []] Con a -> String -> Q [Match] forall a. HasCallStack => String -> a error (String -> Q [Match]) -> String -> Q [Match] forall a b. (a -> b) -> a -> b $ String "deriveArgDict matches: Unmatched 'Dec': " String -> String -> String forall a. [a] -> [a] -> [a] ++ Con -> String forall a. Show a => a -> String show Con a conPCompat :: Name -> [Pat] -> Pat conPCompat :: Name -> [Pat] -> Pat conPCompat Name name = Name -> [Pat] -> Pat ConP Name name #if MIN_VERSION_template_haskell(2, 18, 0) [] #endif kindArity :: Kind -> Int kindArity :: Type -> Int kindArity = \case ForallT [TyVarBndr Specificity] _ [Type] _ Type t -> Type -> Int kindArity Type t AppT (AppT Type ArrowT Type _) Type t -> Int 1 Int -> Int -> Int forall a. Num a => a -> a -> a + Type -> Int kindArity Type t SigT Type t Type _ -> Type -> Int kindArity Type t ParensT Type t -> Type -> Int kindArity Type t Type _ -> Int 0 getDeclInfo :: Name -> Q (Type, [Con]) getDeclInfo :: Name -> Q (Type, [Con]) getDeclInfo Name n = Name -> Q Info reify Name n Q Info -> (Info -> Q (Type, [Con])) -> Q (Type, [Con]) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b >>= \case TyConI (DataD [Type] _ Name _ [TyVarBndr ()] ts Maybe Type mk [Con] constrs [DerivClause] _) -> do let arity :: Int arity = Int -> Maybe Int -> Int forall a. a -> Maybe a -> a fromMaybe Int 0 ((Type -> Int) -> Maybe Type -> Maybe Int forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap Type -> Int kindArity Maybe Type mk) Int -> Int -> Int forall a. Num a => a -> a -> a + [TyVarBndr ()] -> Int forall (t :: * -> *) a. Foldable t => t a -> Int length [TyVarBndr ()] ts [Name] tyVars <- Int -> Q Name -> Q [Name] forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a] replicateM (Int arity Int -> Int -> Int forall a. Num a => a -> a -> a - Int 1) (String -> Q Name forall (m :: * -> *). Quote m => String -> m Name newName String "a") let typeHead :: Type typeHead = (Name -> Type -> Type) -> Type -> [Name] -> Type forall (t :: * -> *) a b. Foldable t => (a -> b -> b) -> b -> t a -> b foldr (\Name v Type x -> Type -> Type -> Type AppT Type x (Name -> Type VarT Name v)) (Name -> Type ConT Name n) [Name] tyVars (Type, [Con]) -> Q (Type, [Con]) forall (m :: * -> *) a. Monad m => a -> m a return (Type typeHead, [Con] constrs) DataConI Name _ (AppT Type typeHead Type _) Name parent -> Type -> Name -> Q (Type, [Con]) forall {a}. a -> Name -> Q (a, [Con]) handleParent Type typeHead Name parent DataConI Name _ (ForallT [TyVarBndr Specificity] _ [Type] _ (AppT Type typeHead Type _)) Name parent -> Type -> Name -> Q (Type, [Con]) forall {a}. a -> Name -> Q (a, [Con]) handleParent Type typeHead Name parent Info a -> String -> Q (Type, [Con]) forall a. HasCallStack => String -> a error (String -> Q (Type, [Con])) -> String -> Q (Type, [Con]) forall a b. (a -> b) -> a -> b $ String "getDeclInfo: Unmatched 'Info': " String -> String -> String forall a. [a] -> [a] -> [a] ++ Info -> String forall a. Show a => a -> String show Info a where handleParent :: a -> Name -> Q (a, [Con]) handleParent a typeHead Name parent = Name -> Q Info reify Name parent Q Info -> (Info -> Q (a, [Con])) -> Q (a, [Con]) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b >>= \case FamilyI Dec _ [Dec] instances -> do let instCons :: InstanceDec -> [Con] instCons :: Dec -> [Con] instCons = \case DataInstD [Type] _ Maybe [TyVarBndr ()] _ Type _ Maybe Type _ [Con] cons [DerivClause] _ -> [Con] cons NewtypeInstD [Type] _ Maybe [TyVarBndr ()] _ Type _ Maybe Type _ Con con [DerivClause] _ -> [Con con] Dec _ -> String -> [Con] forall a. HasCallStack => String -> a error (String -> [Con]) -> String -> [Con] forall a b. (a -> b) -> a -> b $ String "getDeclInfo: Expected a data or newtype family instance" conNames :: Con -> [Name] conNames :: Con -> [Name] conNames = \case NormalC Name other [BangType] _ -> [Name other] RecC Name other [VarBangType] _ -> [Name other] InfixC BangType _ Name other BangType _ -> [Name other] ForallC [TyVarBndr Specificity] _ [Type] _ Con con -> Con -> [Name] conNames Con con GadtC [Name] others [BangType] _ Type _ -> [Name] others RecGadtC [Name] others [VarBangType] _ Type _ -> [Name] others instHasThisConstructor :: Dec -> Bool instHasThisConstructor Dec i = (Name -> Bool) -> [Name] -> Bool forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool any (Name -> Name -> Bool forall a. Eq a => a -> a -> Bool == Name n) ([Name] -> Bool) -> [Name] -> Bool forall a b. (a -> b) -> a -> b $ Con -> [Name] conNames (Con -> [Name]) -> [Con] -> [Name] forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b =<< Dec -> [Con] instCons Dec i case (Dec -> Bool) -> [Dec] -> [Dec] forall a. (a -> Bool) -> [a] -> [a] filter Dec -> Bool instHasThisConstructor [Dec] instances of [] -> String -> Q (a, [Con]) forall a. HasCallStack => String -> a error (String -> Q (a, [Con])) -> String -> Q (a, [Con]) forall a b. (a -> b) -> a -> b $ String "getDeclInfo: Couldn't find data family instance for constructor " String -> String -> String forall a. [a] -> [a] -> [a] ++ Name -> String forall a. Show a => a -> String show Name n l :: [Dec] l@(Dec _:Dec _:[Dec] _) -> String -> Q (a, [Con]) forall a. HasCallStack => String -> a error (String -> Q (a, [Con])) -> String -> Q (a, [Con]) forall a b. (a -> b) -> a -> b $ String "getDeclInfo: Expected one data family instance for constructor " String -> String -> String forall a. [a] -> [a] -> [a] ++ Name -> String forall a. Show a => a -> String show Name n String -> String -> String forall a. [a] -> [a] -> [a] ++ String " but found multiple: " String -> String -> String forall a. [a] -> [a] -> [a] ++ [Dec] -> String forall a. Show a => a -> String show [Dec] l [Dec i] -> (a, [Con]) -> Q (a, [Con]) forall (m :: * -> *) a. Monad m => a -> m a return (a typeHead, Dec -> [Con] instCons Dec i) Info a -> String -> Q (a, [Con]) forall a. HasCallStack => String -> a error (String -> Q (a, [Con])) -> String -> Q (a, [Con]) forall a b. (a -> b) -> a -> b $ String "getDeclInfo: Unmatched parent of data family instance: " String -> String -> String forall a. [a] -> [a] -> [a] ++ Info -> String forall a. Show a => a -> String show Info a gadtIndices :: Name -> [Con] -> Q [Either Type Type] gadtIndices :: Name -> [Con] -> Q [Either Type Type] gadtIndices Name c [Con] constrs = ([[Either Type Type]] -> [Either Type Type]) -> Q [[Either Type Type]] -> Q [Either Type Type] forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap [[Either Type Type]] -> [Either Type Type] forall (t :: * -> *) a. Foldable t => t [a] -> [a] concat (Q [[Either Type Type]] -> Q [Either Type Type]) -> Q [[Either Type Type]] -> Q [Either Type Type] forall a b. (a -> b) -> a -> b $ [Con] -> (Con -> Q [Either Type Type]) -> Q [[Either Type Type]] forall (t :: * -> *) (m :: * -> *) a b. (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b) forM [Con] constrs ((Con -> Q [Either Type Type]) -> Q [[Either Type Type]]) -> (Con -> Q [Either Type Type]) -> Q [[Either Type Type]] forall a b. (a -> b) -> a -> b $ \case GadtC [Name] _ [BangType] _ (AppT Type _ Type typ) -> [Either Type Type] -> Q [Either Type Type] forall (m :: * -> *) a. Monad m => a -> m a return [Type -> Either Type Type forall a b. b -> Either a b Right Type typ] ForallC [TyVarBndr Specificity] _ [Type] _ (GadtC [Name] _ [BangType] bts (AppT Type _ (VarT Name _))) -> ([[Either Type Type]] -> [Either Type Type]) -> Q [[Either Type Type]] -> Q [Either Type Type] forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap [[Either Type Type]] -> [Either Type Type] forall (t :: * -> *) a. Foldable t => t [a] -> [a] concat (Q [[Either Type Type]] -> Q [Either Type Type]) -> Q [[Either Type Type]] -> Q [Either Type Type] forall a b. (a -> b) -> a -> b $ [BangType] -> (BangType -> Q [Either Type Type]) -> Q [[Either Type Type]] forall (t :: * -> *) (m :: * -> *) a b. (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b) forM [BangType] bts ((BangType -> Q [Either Type Type]) -> Q [[Either Type Type]]) -> (BangType -> Q [Either Type Type]) -> Q [[Either Type Type]] forall a b. (a -> b) -> a -> b $ \case (Bang _, AppT Type t (VarT Name _)) -> do Bool hasArgDictInstance <- ([Dec] -> Bool) -> Q [Dec] -> Q Bool forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap (Bool -> Bool not (Bool -> Bool) -> ([Dec] -> Bool) -> [Dec] -> Bool forall b c a. (b -> c) -> (a -> b) -> a -> c . [Dec] -> Bool forall (t :: * -> *) a. Foldable t => t a -> Bool null) (Q [Dec] -> Q Bool) -> Q [Dec] -> Q Bool forall a b. (a -> b) -> a -> b $ Name -> [Type] -> Q [Dec] reifyInstances ''Has [Name -> Type VarT Name c, Type t] [Either Type Type] -> Q [Either Type Type] forall (m :: * -> *) a. Monad m => a -> m a return ([Either Type Type] -> Q [Either Type Type]) -> [Either Type Type] -> Q [Either Type Type] forall a b. (a -> b) -> a -> b $ if Bool hasArgDictInstance then [Type -> Either Type Type forall a b. a -> Either a b Left Type t] else [] BangType _ -> [Either Type Type] -> Q [Either Type Type] forall (m :: * -> *) a. Monad m => a -> m a return [] ForallC [TyVarBndr Specificity] _ [Type] _ (GadtC [Name] _ [BangType] _ (AppT Type _ Type typ)) -> [Either Type Type] -> Q [Either Type Type] forall (m :: * -> *) a. Monad m => a -> m a return [Type -> Either Type Type forall a b. b -> Either a b Right Type typ] Con _ -> [Either Type Type] -> Q [Either Type Type] forall (m :: * -> *) a. Monad m => a -> m a return []