{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE CPP #-}
--------------------------------------------------------------------------------
-- |
-- Module      :  Data.Comp.Derive.Utils
-- Copyright   :  (c) 2010-2011 Patrick Bahr
-- License     :  BSD3
-- Maintainer  :  Patrick Bahr <paba@diku.dk>
-- Stability   :  experimental
-- Portability :  non-portable (GHC Extensions)
--
-- This module defines some utility functions for deriving instances
-- for functor based type classes.
--
--------------------------------------------------------------------------------
module Data.Comp.Derive.Utils where


import Control.Monad
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.ExpandSyns

data DataInfo = forall flag . DataInfo Cxt Name [TyVarBndr flag] [Con] [DerivClause] 


{-|
  This is the @Q@-lifted version of 'abstractNewtype.
-}
abstractNewtypeQ :: Q Info -> Q (Maybe DataInfo)
abstractNewtypeQ :: Q Info -> Q (Maybe DataInfo)
abstractNewtypeQ = forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM Info -> Maybe DataInfo
abstractNewtype

{-|
  This function abstracts away @newtype@ declaration, it turns them into
  @data@ declarations.
-}
abstractNewtype :: Info -> Maybe DataInfo
abstractNewtype :: Info -> Maybe DataInfo
abstractNewtype (TyConI (NewtypeD Cxt
cxt Name
name [TyVarBndr ()]
args Maybe Type
_ Con
constr [DerivClause]
derive))
    = forall a. a -> Maybe a
Just (forall flag.
Cxt
-> Name -> [TyVarBndr flag] -> [Con] -> [DerivClause] -> DataInfo
DataInfo Cxt
cxt Name
name [TyVarBndr ()]
args [Con
constr] [DerivClause]
derive)
abstractNewtype (TyConI (DataD Cxt
cxt Name
name [TyVarBndr ()]
args Maybe Type
_ [Con]
constrs [DerivClause]
derive))
    = forall a. a -> Maybe a
Just (forall flag.
Cxt
-> Name -> [TyVarBndr flag] -> [Con] -> [DerivClause] -> DataInfo
DataInfo Cxt
cxt Name
name [TyVarBndr ()]
args [Con]
constrs [DerivClause]
derive)
abstractNewtype Info
_ = forall a. Maybe a
Nothing

{-| This function provides the name and the arity of the given data
constructor, and if it is a GADT also its type.
-}
normalCon :: Con -> (Name,[StrictType], Maybe Type)
normalCon :: Con -> (Name, [StrictType], Maybe Type)
normalCon (NormalC Name
constr [StrictType]
args) = (Name
constr, [StrictType]
args, forall a. Maybe a
Nothing)
normalCon (RecC Name
constr [VarBangType]
args) = (Name
constr, forall a b. (a -> b) -> [a] -> [b]
map (\(Name
_,Bang
s,Type
t) -> (Bang
s,Type
t)) [VarBangType]
args, forall a. Maybe a
Nothing)
normalCon (InfixC StrictType
a Name
constr StrictType
b) = (Name
constr, [StrictType
a,StrictType
b], forall a. Maybe a
Nothing)
normalCon (ForallC [TyVarBndr Specificity]
_ Cxt
_ Con
constr) = Con -> (Name, [StrictType], Maybe Type)
normalCon Con
constr
normalCon (GadtC (Name
constr:[Name]
_) [StrictType]
args Type
typ) = (Name
constr,[StrictType]
args,forall a. a -> Maybe a
Just Type
typ)
normalCon Con
_ = forall a. HasCallStack => [Char] -> a
error [Char]
"missing case for 'normalCon'"

normalCon' :: Con -> (Name,[Type], Maybe Type)
normalCon' :: Con -> (Name, Cxt, Maybe Type)
normalCon' Con
con = (Name
n, forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd [StrictType]
ts, Maybe Type
t)
  where (Name
n, [StrictType]
ts, Maybe Type
t) = Con -> (Name, [StrictType], Maybe Type)
normalCon Con
con
      

-- -- | Same as normalCon' but expands type synonyms.
-- normalConExp :: Con -> Q (Name,[Type])
-- normalConExp c = do
--   let (n,ts,t) = normalCon' c
--   ts' <- mapM expandSyns ts
--   return (n, ts')

-- | Same as normalCon' but expands type synonyms.
normalConExp :: Con -> Q (Name,[Type], Maybe Type)
normalConExp :: Con -> Q (Name, Cxt, Maybe Type)
normalConExp Con
c = do
  let (Name
n,Cxt
ts,Maybe Type
t) = Con -> (Name, Cxt, Maybe Type)
normalCon' Con
c
  forall (m :: * -> *) a. Monad m => a -> m a
return (Name
n, Cxt
ts,Maybe Type
t)


-- | Same as normalConExp' but retains strictness annotations.
normalConStrExp :: Con -> Q (Name,[StrictType], Maybe Type)
normalConStrExp :: Con -> Q (Name, [StrictType], Maybe Type)
normalConStrExp Con
c = do
  let (Name
n,[StrictType]
ts,Maybe Type
t) = Con -> (Name, [StrictType], Maybe Type)
normalCon Con
c
  [StrictType]
ts' <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (\ (Bang
st,Type
ty) -> do Type
ty' <- Type -> Q Type
expandSyns Type
ty; forall (m :: * -> *) a. Monad m => a -> m a
return (Bang
st,Type
ty')) [StrictType]
ts
  forall (m :: * -> *) a. Monad m => a -> m a
return (Name
n, [StrictType]
ts',Maybe Type
t)

-- | Auxiliary function to extract the first argument of a binary type
-- application (the second argument of this function). If the second
-- argument is @Nothing@ or not of the right shape, the first argument
-- is returned as a default.

getBinaryFArg :: Type -> Maybe Type -> Type
getBinaryFArg :: Type -> Maybe Type -> Type
getBinaryFArg Type
_ (Just (AppT (AppT Type
_ Type
t)  Type
_)) = Type
t
getBinaryFArg Type
def Maybe Type
_ = Type
def

-- | Auxiliary function to extract the first argument of a type
-- application (the second argument of this function). If the second
-- argument is @Nothing@ or not of the right shape, the first argument
-- is returned as a default.
getUnaryFArg :: Type -> Maybe Type -> Type
getUnaryFArg :: Type -> Maybe Type -> Type
getUnaryFArg Type
_ (Just (AppT Type
_ Type
t)) = Type
t
getUnaryFArg Type
def Maybe Type
_ = Type
def



{-|
  This function provides the name and the arity of the given data constructor.
-}
abstractConType :: Con -> (Name,Int)
abstractConType :: Con -> (Name, Int)
abstractConType (NormalC Name
constr [StrictType]
args) = (Name
constr, forall (t :: * -> *) a. Foldable t => t a -> Int
length [StrictType]
args)
abstractConType (RecC Name
constr [VarBangType]
args) = (Name
constr, forall (t :: * -> *) a. Foldable t => t a -> Int
length [VarBangType]
args)
abstractConType (InfixC StrictType
_ Name
constr StrictType
_) = (Name
constr, Int
2)
abstractConType (ForallC [TyVarBndr Specificity]
_ Cxt
_ Con
constr) = Con -> (Name, Int)
abstractConType Con
constr
abstractConType (GadtC (Name
constr:[Name]
_) [StrictType]
args Type
_typ) = (Name
constr,forall (t :: * -> *) a. Foldable t => t a -> Int
length [StrictType]
args) -- Only first Name
abstractConType Con
_ = forall a. HasCallStack => [Char] -> a
error [Char]
"missing case for 'abstractConType'"

{-|
  This function returns the name of a bound type variable
-}
tyVarBndrName :: TyVarBndr flag -> Name
tyVarBndrName (PlainTV Name
n flag
_) = Name
n
tyVarBndrName (KindedTV Name
n flag
_ Type
_) = Name
n

containsType :: Type -> Type -> Bool
containsType :: Type -> Type -> Bool
containsType Type
s Type
t
             | Type
s forall a. Eq a => a -> a -> Bool
== Type
t = Bool
True
             | Bool
otherwise = case Type
s of
                             ForallT [TyVarBndr Specificity]
_ Cxt
_ Type
s' -> Type -> Type -> Bool
containsType Type
s' Type
t
                             AppT Type
s1 Type
s2 -> Type -> Type -> Bool
containsType Type
s1 Type
t Bool -> Bool -> Bool
|| Type -> Type -> Bool
containsType Type
s2 Type
t
                             SigT Type
s' Type
_ -> Type -> Type -> Bool
containsType Type
s' Type
t
                             Type
_ -> Bool
False

containsType' :: Type -> Type -> [Int]
containsType' :: Type -> Type -> [Int]
containsType' = forall {t}. Num t => t -> Type -> Type -> [t]
run Int
0
    where run :: t -> Type -> Type -> [t]
run t
n Type
s Type
t
             | Type
s forall a. Eq a => a -> a -> Bool
== Type
t = [t
n]
             | Bool
otherwise = case Type
s of
                             ForallT [TyVarBndr Specificity]
_ Cxt
_ Type
s' -> t -> Type -> Type -> [t]
run t
n Type
s' Type
t
                             -- only going through the right-hand side counts!
                             AppT Type
s1 Type
s2 -> t -> Type -> Type -> [t]
run t
n Type
s1 Type
t forall a. [a] -> [a] -> [a]
++ t -> Type -> Type -> [t]
run (t
nforall a. Num a => a -> a -> a
+t
1) Type
s2 Type
t
                             SigT Type
s' Type
_ -> t -> Type -> Type -> [t]
run t
n Type
s' Type
t
                             Type
_ -> []


{-|
  This function provides a list (of the given length) of new names based
  on the given string.
-}
newNames :: Int -> String -> Q [Name]
newNames :: Int -> [Char] -> Q [Name]
newNames Int
n [Char]
name = forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM Int
n (forall (m :: * -> *). Quote m => [Char] -> m Name
newName [Char]
name)

tupleTypes :: Int -> Int -> [Name]
tupleTypes Int
n Int
m = forall a b. (a -> b) -> [a] -> [b]
map Int -> Name
tupleTypeName [Int
n..Int
m]

{-| Helper function for generating a list of instances for a list of named
 signatures. For example, in order to derive instances 'Functor' and
 'ShowF' for a signature @Exp@, use derive as follows (requires Template
 Haskell):

 > $(derive [makeFunctor, makeShowF] [''Exp])
 -}
derive :: [Name -> Q [Dec]] -> [Name] -> Q [Dec]
derive :: [Name -> Q [Dec]] -> [Name] -> Q [Dec]
derive [Name -> Q [Dec]]
ders [Name]
names = forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence [Name -> Q [Dec]
der Name
name | Name -> Q [Dec]
der <- [Name -> Q [Dec]]
ders, Name
name <- [Name]
names]

{-| Apply a class name to type arguments to construct a type class
    constraint.
-}

mkClassP :: Name -> [Type] -> Type
mkClassP :: Name -> Cxt -> Type
mkClassP Name
name = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl Type -> Type -> Type
AppT (Name -> Type
ConT Name
name)

{-| This function checks whether the given type constraint is an
equality constraint. If so, the types of the equality constraint are
returned. -}

isEqualP :: Type -> Maybe (Type, Type)
isEqualP :: Type -> Maybe (Type, Type)
isEqualP (AppT (AppT Type
EqualityT Type
x) Type
y) = forall a. a -> Maybe a
Just (Type
x, Type
y)
isEqualP Type
_ = forall a. Maybe a
Nothing

mkInstanceD :: Cxt -> Type -> [Dec] -> Dec
mkInstanceD :: Cxt -> Type -> [Dec] -> Dec
mkInstanceD Cxt
cxt Type
ty [Dec]
decs = Maybe Overlap -> Cxt -> Type -> [Dec] -> Dec
InstanceD forall a. Maybe a
Nothing Cxt
cxt Type
ty [Dec]
decs



-- | This function lifts type class instances over sums
-- ofsignatures. To this end it assumes that it contains only methods
-- with types of the form @f t1 .. tn -> t@ where @f@ is the signature
-- that is used to construct sums. Since this function is generic it
-- assumes as its first argument the name of the function that is
-- used to lift methods over sums i.e. a function of type
--
-- @
-- (f t1 .. tn -> t) -> (g t1 .. tn -> t) -> ((f :+: g) t1 .. tn -> t)
-- @
--
-- where @:+:@ is the sum type constructor. The second argument to
-- this function is expected to be the name of that constructor. The
-- last argument is the name of the class whose instances should be
-- lifted over sums.

liftSumGen :: Name -> Name -> Name -> Q [Dec]
liftSumGen :: Name -> Name -> Name -> Q [Dec]
liftSumGen Name
caseName Name
sumName Name
fname = do
  ClassI (ClassD Cxt
_ Name
name [TyVarBndr ()]
targs_ [FunDep]
_ [Dec]
decs) [Dec]
_ <- Name -> Q Info
reify Name
fname
  let targs :: [Name]
targs = forall a b. (a -> b) -> [a] -> [b]
map forall {flag}. TyVarBndr flag -> Name
tyVarBndrName [TyVarBndr ()]
targs_
  Maybe ([Name], [Name])
splitM <- [Name] -> [Dec] -> Q (Maybe ([Name], [Name]))
findSig [Name]
targs [Dec]
decs
  case Maybe ([Name], [Name])
splitM of
    Maybe ([Name], [Name])
Nothing -> do [Char] -> Q ()
reportError forall a b. (a -> b) -> a -> b
$ [Char]
"Class " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show Name
name forall a. [a] -> [a] -> [a]
++ [Char]
" cannot be lifted to sums!"
                  forall (m :: * -> *) a. Monad m => a -> m a
return []
    Just ([Name]
ts1_, [Name]
ts2_) -> do
      let f :: Type
f = Name -> Type
VarT forall a b. (a -> b) -> a -> b
$ [Char] -> Name
mkName [Char]
"f"
      let g :: Type
g = Name -> Type
VarT forall a b. (a -> b) -> a -> b
$ [Char] -> Name
mkName [Char]
"g"
      let ts1 :: Cxt
ts1 = forall a b. (a -> b) -> [a] -> [b]
map Name -> Type
VarT [Name]
ts1_
      let ts2 :: Cxt
ts2 = forall a b. (a -> b) -> [a] -> [b]
map Name -> Type
VarT [Name]
ts2_
      let cxt :: Cxt
cxt = [Name -> Cxt -> Type
mkClassP Name
name (Cxt
ts1 forall a. [a] -> [a] -> [a]
++ Type
f forall a. a -> [a] -> [a]
: Cxt
ts2),
                 Name -> Cxt -> Type
mkClassP Name
name (Cxt
ts1 forall a. [a] -> [a] -> [a]
++ Type
g forall a. a -> [a] -> [a]
: Cxt
ts2)]
      let tp :: Type
tp = ((Name -> Type
ConT Name
sumName Type -> Type -> Type
`AppT` Type
f) Type -> Type -> Type
`AppT` Type
g)
      let complType :: Type
complType = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl Type -> Type -> Type
AppT (forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl Type -> Type -> Type
AppT (Name -> Type
ConT Name
name) Cxt
ts1 Type -> Type -> Type
`AppT` Type
tp) Cxt
ts2
      [Dec]
decs' <- forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Dec -> [DecQ]
decl [Dec]
decs
      forall (m :: * -> *) a. Monad m => a -> m a
return [Cxt -> Type -> [Dec] -> Dec
mkInstanceD Cxt
cxt Type
complType [Dec]
decs']
        where decl :: Dec -> [DecQ]
              decl :: Dec -> [DecQ]
decl (SigD Name
f Type
_) = [forall (m :: * -> *). Quote m => Name -> [m Clause] -> m Dec
funD Name
f [Name -> Q Clause
clause Name
f]]
              decl Dec
_ = []
              clause :: Name -> ClauseQ
              clause :: Name -> Q Clause
clause Name
f = do Name
x <- forall (m :: * -> *). Quote m => [Char] -> m Name
newName [Char]
"x"
                            let b :: Body
b = Exp -> Body
NormalB (Name -> Exp
VarE Name
caseName Exp -> Exp -> Exp
`AppE` Name -> Exp
VarE Name
f Exp -> Exp -> Exp
`AppE` Name -> Exp
VarE Name
f Exp -> Exp -> Exp
`AppE` Name -> Exp
VarE Name
x)
                            forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ [Pat] -> Body -> [Dec] -> Clause
Clause [Name -> Pat
VarP Name
x] Body
b []


findSig :: [Name] -> [Dec] -> Q (Maybe ([Name],[Name]))
findSig :: [Name] -> [Dec] -> Q (Maybe ([Name], [Name]))
findSig [Name]
targs [Dec]
decs = case forall a b. (a -> b) -> [a] -> [b]
map Dec -> Q (Maybe Name)
run [Dec]
decs of
                       []  -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
                       Q (Maybe Name)
mx:[Q (Maybe Name)]
_ -> do Maybe Name
x <- Q (Maybe Name)
mx
                                  case Maybe Name
x of
                                    Maybe Name
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
                                    Just Name
n -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall {a}. Eq a => a -> [a] -> Maybe ([a], [a])
splitNames Name
n [Name]
targs
  where run :: Dec -> Q (Maybe Name)
        run :: Dec -> Q (Maybe Name)
run (SigD Name
_ Type
ty) = do
          Type
ty' <- Type -> Q Type
expandSyns Type
ty
          forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Bool -> Type -> Maybe Name
getSig Bool
False Type
ty'
        run Dec
_ = forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
        getSig :: Bool -> Type -> Maybe Name
getSig Bool
t (ForallT [TyVarBndr Specificity]
_ Cxt
_ Type
ty) = Bool -> Type -> Maybe Name
getSig Bool
t Type
ty
        getSig Bool
False (AppT (AppT Type
ArrowT Type
ty) Type
_) = Bool -> Type -> Maybe Name
getSig Bool
True Type
ty
        getSig Bool
True (AppT Type
ty Type
_) = Bool -> Type -> Maybe Name
getSig Bool
True Type
ty
        getSig Bool
True (VarT Name
n) = forall a. a -> Maybe a
Just Name
n
        getSig Bool
_ Type
_ = forall a. Maybe a
Nothing
        splitNames :: a -> [a] -> Maybe ([a], [a])
splitNames a
y (a
x:[a]
xs)
          | a
y forall a. Eq a => a -> a -> Bool
== a
x = forall a. a -> Maybe a
Just ([],[a]
xs)
          | Bool
otherwise = do ([a]
xs1,[a]
xs2) <- a -> [a] -> Maybe ([a], [a])
splitNames a
y [a]
xs
                           forall (m :: * -> *) a. Monad m => a -> m a
return (a
xforall a. a -> [a] -> [a]
:[a]
xs1,[a]
xs2)
        splitNames a
_ [] = forall a. Maybe a
Nothing