{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskellQuotes #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Use <=<" #-}
module Data.Effect.HFunctor.TH.Internal where
import Control.Monad (replicateM, zipWithM)
import Data.Effect (EffectForm (Exponential, Polynomial), FormOf, PolyHFunctor)
import Data.Effect.HFunctor (HFunctor, hfmap)
import Data.Effect.TH.Internal (
ConInfo (ConInfo),
DataInfo (DataInfo),
conArgs,
conGadtReturnType,
conName,
occurs,
tyVarName,
tyVarType,
unkindType,
)
import Data.Foldable (foldl')
import Data.Functor ((<&>))
import Data.List.Infinite (Infinite, prependList)
import Data.Maybe (fromMaybe)
import Data.Text qualified as T
import Language.Haskell.TH (
Body (NormalB),
Clause (Clause),
Dec (FunD, InstanceD, PragmaD),
Exp (AppE, CaseE, ConE, LamE, TupE, VarE),
Inline (Inline),
Match (Match),
Name,
Pat (ConP, TupP, VarP),
Phases (AllPhases),
Pragma (InlineP),
Q,
Quote (..),
RuleMatch (FunLike),
TyVarBndr (PlainTV),
Type (AppT, ArrowT, ConT, ForallT, SigT, TupleT, VarT),
appE,
nameBase,
pprint,
)
import Language.Haskell.TH qualified as TH
deriveHFunctor :: (Infinite (Q TH.Type) -> Q TH.Type) -> DataInfo -> Q [Dec]
deriveHFunctor :: (Infinite (Q Type) -> Q Type) -> DataInfo -> Q [Dec]
deriveHFunctor Infinite (Q Type) -> Q Type
manualCxt (DataInfo Cxt
_ Name
name [TyVarBndr ()]
args [ConInfo]
cons) = do
Name
mapFnName <- [Char] -> Q Name
forall (m :: * -> *). Quote m => [Char] -> m Name
newName [Char]
"_f"
let mapFn :: Exp
mapFn = Name -> Exp
VarE Name
mapFnName
initArgs :: [TyVarBndr ()]
initArgs = [TyVarBndr ()] -> [TyVarBndr ()]
forall a. HasCallStack => [a] -> [a]
init [TyVarBndr ()]
args
hfArgs :: [TyVarBndr ()]
hfArgs = [TyVarBndr ()] -> [TyVarBndr ()]
forall a. HasCallStack => [a] -> [a]
init [TyVarBndr ()]
initArgs
hfArgNames :: Cxt
hfArgNames = (TyVarBndr () -> Type) -> [TyVarBndr ()] -> Cxt
forall a b. (a -> b) -> [a] -> [b]
map (Name -> Type
VarT (Name -> Type) -> (TyVarBndr () -> Name) -> TyVarBndr () -> Type
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TyVarBndr () -> Name
forall a. TyVarBndr a -> Name
tyVarName) [TyVarBndr ()]
hfArgs
hfmapClause :: ConInfo -> Q (Bool, Clause)
hfmapClause :: ConInfo -> Q (Bool, Clause)
hfmapClause ConInfo{[BangType]
Maybe Type
Name
conArgs :: ConInfo -> [BangType]
conGadtReturnType :: ConInfo -> Maybe Type
conName :: ConInfo -> Name
conName :: Name
conArgs :: [BangType]
conGadtReturnType :: Maybe Type
..} = do
let f :: TyVarBndr ()
f = case Maybe Type
conGadtReturnType of
Maybe Type
Nothing -> [TyVarBndr ()] -> TyVarBndr ()
forall a. HasCallStack => [a] -> a
last [TyVarBndr ()]
initArgs
Just Type
t -> case Type
t of
Type
_ `AppT` VarT Name
n `AppT` Type
_ -> Name -> () -> TyVarBndr ()
forall flag. Name -> flag -> TyVarBndr flag
PlainTV Name
n ()
Type
_ `AppT` (VarT Name
n `SigT` Type
_) `AppT` Type
_ -> Name -> () -> TyVarBndr ()
forall flag. Name -> flag -> TyVarBndr flag
PlainTV Name
n ()
Type
_ -> [Char] -> TyVarBndr ()
forall a. HasCallStack => [Char] -> a
error ([Char] -> TyVarBndr ()) -> [Char] -> TyVarBndr ()
forall a b. (a -> b) -> a -> b
$ [Char]
"Encounted unknown structure: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Type -> [Char]
forall a. Ppr a => a -> [Char]
pprint Type
t
hfmapE :: TH.Type -> Exp -> Q (Bool, Exp)
hfmapE :: Type -> Exp -> Q (Bool, Exp)
hfmapE Type
tk
| Type -> Bool
fNotOccurs Type
t = (Bool, Exp) -> Q (Bool, Exp)
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((Bool, Exp) -> Q (Bool, Exp))
-> (Exp -> (Bool, Exp)) -> Exp -> Q (Bool, Exp)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bool
True,)
| Bool
otherwise = \Exp
x -> case Type
t of
VarT Name
n `AppT` Type
a | Name
n Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
== TyVarBndr () -> Name
forall a. TyVarBndr a -> Name
tyVarName TyVarBndr ()
f Bool -> Bool -> Bool
&& Type -> Bool
fNotOccurs Type
a -> (Bool, Exp) -> Q (Bool, Exp)
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool
True, Exp
mapFn Exp -> Exp -> Exp
`AppE` Exp
x)
Type
ArrowT `AppT` Type
c `AppT` Type
d ->
(Bool
False,) (Exp -> (Bool, Exp)) -> Q Exp -> Q (Bool, Exp)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Exp -> Q Exp) -> Q Exp
wrapLam \Exp
y -> ((Bool, Exp) -> Exp) -> Q (Bool, Exp) -> Q Exp
forall a b. (a -> b) -> Q a -> Q b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Bool, Exp) -> Exp
forall a b. (a, b) -> b
snd (Q (Bool, Exp) -> Q Exp) -> (Exp -> Q (Bool, Exp)) -> Exp -> Q Exp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Type -> Exp -> Q (Bool, Exp)
hfmapE Type
d (Exp -> Q (Bool, Exp)) -> (Exp -> Exp) -> Exp -> Q (Bool, Exp)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Exp
x `AppE`) (Exp -> Q Exp) -> Q Exp -> Q Exp
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Type -> Exp -> Q Exp
cohfmapE Type
c Exp
y
Type
g `AppT` Type
a
| Type -> Bool
fNotOccurs Type
g ->
(Bool
True,) (Exp -> (Bool, Exp)) -> Q Exp -> Q (Bool, Exp)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (((Name -> Exp
VarE 'fmap `AppE`) (Exp -> Exp) -> Q Exp -> Q Exp
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Exp -> Q Exp) -> Q Exp
wrapLam (((Bool, Exp) -> Exp) -> Q (Bool, Exp) -> Q Exp
forall a b. (a -> b) -> Q a -> Q b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Bool, Exp) -> Exp
forall a b. (a, b) -> b
snd (Q (Bool, Exp) -> Q Exp) -> (Exp -> Q (Bool, Exp)) -> Exp -> Q Exp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Type -> Exp -> Q (Bool, Exp)
hfmapE Type
a)) Q Exp -> (Exp -> Exp) -> Q Exp
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> (Exp -> Exp -> Exp
`AppE` Exp
x))
Type
ff `AppT` Type
g `AppT` Type
a
| Type -> Bool
fNotOccurs Type
ff Bool -> Bool -> Bool
&& Type -> Bool
fNotOccurs Type
a ->
(Bool
True,) (Exp -> (Bool, Exp)) -> Q Exp -> Q (Bool, Exp)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (((Name -> Exp
VarE 'hfmap `AppE`) (Exp -> Exp) -> Q Exp -> Q Exp
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Exp -> Q Exp) -> Q Exp
wrapLam (((Bool, Exp) -> Exp) -> Q (Bool, Exp) -> Q Exp
forall a b. (a -> b) -> Q a -> Q b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Bool, Exp) -> Exp
forall a b. (a, b) -> b
snd (Q (Bool, Exp) -> Q Exp) -> (Exp -> Q (Bool, Exp)) -> Exp -> Q Exp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Type -> Exp -> Q (Bool, Exp)
hfmapE (Type
g Type -> Type -> Type
`AppT` Type
a))) Q Exp -> (Exp -> Exp) -> Q Exp
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> (Exp -> Exp -> Exp
`AppE` Exp
x))
ForallT [TyVarBndr Specificity]
_ Cxt
_ Type
a -> Type -> Exp -> Q (Bool, Exp)
hfmapE Type
a Exp
x
Type
_ ->
case (Type -> Exp -> Q Exp) -> Type -> Exp -> Maybe (Q Exp)
mapTupleE ((((Bool, Exp) -> Exp) -> Q (Bool, Exp) -> Q Exp
forall a b. (a -> b) -> Q a -> Q b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Bool, Exp) -> Exp
forall a b. (a, b) -> b
snd .) ((Exp -> Q (Bool, Exp)) -> Exp -> Q Exp)
-> (Type -> Exp -> Q (Bool, Exp)) -> Type -> Exp -> Q Exp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Type -> Exp -> Q (Bool, Exp)
hfmapE) Type
t Exp
x of
Just Q Exp
e -> (Bool
True,) (Exp -> (Bool, Exp)) -> Q Exp -> Q (Bool, Exp)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Q Exp
e
Maybe (Q Exp)
Nothing -> [Char] -> Q (Bool, Exp)
forall a. [Char] -> Q a
forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail ([Char] -> Q (Bool, Exp)) -> [Char] -> Q (Bool, Exp)
forall a b. (a -> b) -> a -> b
$ [Char]
"Encounted unsupported structure: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Type -> [Char]
forall a. Ppr a => a -> [Char]
pprint Type
t
where
t :: Type
t = Type -> Type
unkindType Type
tk
cohfmapE :: TH.Type -> Exp -> Q Exp
cohfmapE :: Type -> Exp -> Q Exp
cohfmapE Type
tk
| Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ TyVarBndr () -> Name
forall a. TyVarBndr a -> Name
tyVarName TyVarBndr ()
f Name -> Type -> Bool
`occurs` Type
t = Exp -> Q Exp
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
| Bool
otherwise = \Exp
x -> case Type
t of
VarT Name
n `AppT` Type
a
| Name
n Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
== TyVarBndr () -> Name
forall a. TyVarBndr a -> Name
tyVarName TyVarBndr ()
f Bool -> Bool -> Bool
&& Type -> Bool
fNotOccurs Type
a ->
[Char] -> Q Exp
forall a. [Char] -> Q a
forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail ([Char] -> Q Exp) -> [Char] -> Q Exp
forall a b. (a -> b) -> a -> b
$ [Char]
"Functor type variable occurs in contravariant position: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Type -> [Char]
forall a. Ppr a => a -> [Char]
pprint Type
t
Type
ArrowT `AppT` Type
c `AppT` Type
d ->
(Exp -> Q Exp) -> Q Exp
wrapLam \Exp
y -> (Type -> Exp -> Q Exp
cohfmapE Type
d (Exp -> Q Exp) -> (Exp -> Exp) -> Exp -> Q Exp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Exp
x `AppE`)) (Exp -> Q Exp) -> ((Bool, Exp) -> Exp) -> (Bool, Exp) -> Q Exp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bool, Exp) -> Exp
forall a b. (a, b) -> b
snd ((Bool, Exp) -> Q Exp) -> Q (Bool, Exp) -> Q Exp
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Type -> Exp -> Q (Bool, Exp)
hfmapE Type
c Exp
y
Type
g `AppT` Type
a
| Type -> Bool
fNotOccurs Type
g ->
((Name -> Exp
VarE 'fmap `AppE`) (Exp -> Exp) -> Q Exp -> Q Exp
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Exp -> Q Exp) -> Q Exp
wrapLam (Type -> Exp -> Q Exp
cohfmapE Type
a)) Q Exp -> (Exp -> Exp) -> Q Exp
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> (Exp -> Exp -> Exp
`AppE` Exp
x)
Type
ff `AppT` Type
_ `AppT` Type
a
| Type -> Bool
fNotOccurs Type
ff Bool -> Bool -> Bool
&& Type -> Bool
fNotOccurs Type
a ->
[Char] -> Q Exp
forall a. [Char] -> Q a
forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail ([Char] -> Q Exp) -> [Char] -> Q Exp
forall a b. (a -> b) -> a -> b
$ [Char]
"Functor type variable occurs in contravariant position: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Type -> [Char]
forall a. Ppr a => a -> [Char]
pprint Type
t
ForallT [TyVarBndr Specificity]
_ Cxt
_ Type
b' -> Type -> Exp -> Q Exp
cohfmapE Type
b' Exp
x
Type
_ ->
case (Type -> Exp -> Q Exp) -> Type -> Exp -> Maybe (Q Exp)
mapTupleE Type -> Exp -> Q Exp
cohfmapE Type
t Exp
x of
Just Q Exp
e -> Q Exp
e
Maybe (Q Exp)
Nothing -> [Char] -> Q Exp
forall a. [Char] -> Q a
forall (m :: * -> *) a. MonadFail m => [Char] -> m a
fail ([Char] -> Q Exp) -> [Char] -> Q Exp
forall a b. (a -> b) -> a -> b
$ [Char]
"Encounted unsupported structure: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Type -> [Char]
forall a. Ppr a => a -> [Char]
pprint Type
t
where
t :: Type
t = Type -> Type
unkindType Type
tk
fNotOccurs :: Type -> Bool
fNotOccurs = Bool -> Bool
not (Bool -> Bool) -> (Type -> Bool) -> Type -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (TyVarBndr () -> Name
forall a. TyVarBndr a -> Name
tyVarName TyVarBndr ()
f `occurs`)
[Name]
vars <- Int -> Q Name -> Q [Name]
forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM ([BangType] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [BangType]
conArgs) ([Char] -> Q Name
forall (m :: * -> *). Quote m => [Char] -> m Name
newName [Char]
"x")
[(Bool, Exp)]
mappedArgs <- (Type -> Exp -> Q (Bool, Exp)) -> Cxt -> [Exp] -> Q [(Bool, Exp)]
forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> m c) -> [a] -> [b] -> m [c]
zipWithM Type -> Exp -> Q (Bool, Exp)
hfmapE ((BangType -> Type) -> [BangType] -> Cxt
forall a b. (a -> b) -> [a] -> [b]
map BangType -> Type
forall a b. (a, b) -> b
snd [BangType]
conArgs) ((Name -> Exp) -> [Name] -> [Exp]
forall a b. (a -> b) -> [a] -> [b]
map Name -> Exp
VarE [Name]
vars)
let body :: Exp
body = (Exp -> Exp -> Exp) -> Exp -> [Exp] -> Exp
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Exp -> Exp -> Exp
AppE (Name -> Exp
ConE Name
conName) (((Bool, Exp) -> Exp) -> [(Bool, Exp)] -> [Exp]
forall a b. (a -> b) -> [a] -> [b]
map (Bool, Exp) -> Exp
forall a b. (a, b) -> b
snd [(Bool, Exp)]
mappedArgs)
isPolynomial :: Bool
isPolynomial = ((Bool, Exp) -> Bool) -> [(Bool, Exp)] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Bool, Exp) -> Bool
forall a b. (a, b) -> a
fst [(Bool, Exp)]
mappedArgs
(Bool, Clause) -> Q (Bool, Clause)
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool
isPolynomial, [Pat] -> Body -> [Dec] -> Clause
Clause [Name -> Pat
VarP Name
mapFnName, Name -> Cxt -> [Pat] -> Pat
ConP Name
conName [] ((Name -> Pat) -> [Name] -> [Pat]
forall a b. (a -> b) -> [a] -> [b]
map Name -> Pat
VarP [Name]
vars)] (Exp -> Body
NormalB Exp
body) [])
Type
cxt <-
Infinite (Q Type) -> Q Type
manualCxt (Infinite (Q Type) -> Q Type) -> Infinite (Q Type) -> Q Type
forall a b. (a -> b) -> a -> b
$
(TyVarBndr () -> Q Type) -> [TyVarBndr ()] -> [Q Type]
forall a b. (a -> b) -> [a] -> [b]
map (Type -> Q Type
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Type -> Q Type)
-> (TyVarBndr () -> Type) -> TyVarBndr () -> Q Type
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TyVarBndr () -> Type
forall a. TyVarBndr a -> Type
tyVarType) [TyVarBndr ()]
hfArgs
[Q Type] -> Infinite (Q Type) -> Infinite (Q Type)
forall a. [a] -> Infinite a -> Infinite a
`prependList` [Char] -> Infinite (Q Type)
forall a. HasCallStack => [Char] -> a
error
( Text -> [Char]
T.unpack (Text -> [Char]) -> Text -> [Char]
forall a b. (a -> b) -> a -> b
$
Text
"Too many data type arguments in use. The number of usable type arguments in the data type ‘"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [Char] -> Text
T.pack (Name -> [Char]
nameBase Name
name)
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"’ to be derived is "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [Char] -> Text
T.pack (Int -> [Char]
forall a. Show a => a -> [Char]
show (Int -> [Char]) -> Int -> [Char]
forall a b. (a -> b) -> a -> b
$ [TyVarBndr ()] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [TyVarBndr ()]
hfArgs)
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
". ("
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> [Text] -> Text
T.intercalate Text
", " ((TyVarBndr () -> Text) -> [TyVarBndr ()] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map ((\Text
t -> Text
"‘" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
t Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"’") (Text -> Text) -> (TyVarBndr () -> Text) -> TyVarBndr () -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> Text
T.pack ([Char] -> Text)
-> (TyVarBndr () -> [Char]) -> TyVarBndr () -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> [Char]
nameBase (Name -> [Char])
-> (TyVarBndr () -> Name) -> TyVarBndr () -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TyVarBndr () -> Name
forall a. TyVarBndr a -> Name
tyVarName) [TyVarBndr ()]
hfArgs)
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
")"
)
[(Bool, Clause)]
hfmapClauses <- (ConInfo -> Q (Bool, Clause)) -> [ConInfo] -> Q [(Bool, Clause)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM ConInfo -> Q (Bool, Clause)
hfmapClause [ConInfo]
cons
let hfmapDecls :: Dec
hfmapDecls = Name -> [Clause] -> Dec
FunD 'hfmap ([Clause] -> Dec) -> [Clause] -> Dec
forall a b. (a -> b) -> a -> b
$ ((Bool, Clause) -> Clause) -> [(Bool, Clause)] -> [Clause]
forall a b. (a -> b) -> [a] -> [b]
map (Bool, Clause) -> Clause
forall a b. (a, b) -> b
snd [(Bool, Clause)]
hfmapClauses
fnInline :: Dec
fnInline = Pragma -> Dec
PragmaD (Name -> Inline -> RuleMatch -> Phases -> Pragma
InlineP 'hfmap Inline
Inline RuleMatch
FunLike Phases
AllPhases)
isPolynomial :: Bool
isPolynomial = ((Bool, Clause) -> Bool) -> [(Bool, Clause)] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Bool, Clause) -> Bool
forall a b. (a, b) -> a
fst [(Bool, Clause)]
hfmapClauses
h :: Type
h = (Type -> Type -> Type) -> Type -> Cxt -> Type
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Type -> Type -> Type
AppT (Name -> Type
ConT Name
name) Cxt
hfArgNames
[Dec]
formOf <-
if Bool
isPolynomial
then
[d|
type instance FormOf $(Type -> Q Type
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Type
h) = 'Polynomial
instance PolyHFunctor $(Type -> Q Type
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Type
h)
|]
else [d|type instance FormOf $(Type -> Q Type
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Type
h) = 'Exponential|]
[Dec] -> Q [Dec]
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([Dec] -> Q [Dec]) -> [Dec] -> Q [Dec]
forall a b. (a -> b) -> a -> b
$
Maybe Overlap -> Cxt -> Type -> [Dec] -> Dec
InstanceD
Maybe Overlap
forall a. Maybe a
Nothing
(Cxt -> Maybe Cxt -> Cxt
forall a. a -> Maybe a -> a
fromMaybe [Type
cxt] (Maybe Cxt -> Cxt) -> Maybe Cxt -> Cxt
forall a b. (a -> b) -> a -> b
$ Type -> Maybe Cxt
decomposeTupleT Type
cxt)
(Name -> Type
ConT ''HFunctor Type -> Type -> Type
`AppT` Type
h)
[Dec
hfmapDecls, Dec
fnInline]
Dec -> [Dec] -> [Dec]
forall a. a -> [a] -> [a]
: [Dec]
formOf
wrapLam :: (Exp -> Q Exp) -> Q Exp
wrapLam :: (Exp -> Q Exp) -> Q Exp
wrapLam Exp -> Q Exp
f = do
Name
x <- [Char] -> Q Name
forall (m :: * -> *). Quote m => [Char] -> m Name
newName [Char]
"x"
[Pat] -> Exp -> Exp
LamE [Name -> Pat
VarP Name
x] (Exp -> Exp) -> Q Exp -> Q Exp
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Exp -> Q Exp
f (Name -> Exp
VarE Name
x)
mapTupleE :: (TH.Type -> Exp -> Q Exp) -> TH.Type -> Exp -> Maybe (Q Exp)
mapTupleE :: (Type -> Exp -> Q Exp) -> Type -> Exp -> Maybe (Q Exp)
mapTupleE Type -> Exp -> Q Exp
f Type
t Exp
e = do
Cxt
es <- Type -> Maybe Cxt
decomposeTupleT Type
t
let n :: Int
n = Cxt -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length Cxt
es
Q Exp -> Maybe (Q Exp)
forall a. a -> Maybe a
Just do
[Name]
xs <- Int -> [Char] -> Q [Name]
newNames Int
n [Char]
"x"
[Exp]
ys <- (Type -> Exp -> Q Exp) -> Cxt -> [Exp] -> Q [Exp]
forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> m c) -> [a] -> [b] -> m [c]
zipWithM Type -> Exp -> Q Exp
f Cxt
es ([Exp] -> Q [Exp]) -> [Exp] -> Q [Exp]
forall a b. (a -> b) -> a -> b
$ (Name -> Exp) -> [Name] -> [Exp]
forall a b. (a -> b) -> [a] -> [b]
map Name -> Exp
VarE [Name]
xs
Exp -> Q Exp
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Exp -> Q Exp) -> Exp -> Q Exp
forall a b. (a -> b) -> a -> b
$ Exp -> [Match] -> Exp
CaseE Exp
e [Pat -> Body -> [Dec] -> Match
Match ([Pat] -> Pat
TupP ([Pat] -> Pat) -> [Pat] -> Pat
forall a b. (a -> b) -> a -> b
$ (Name -> Pat) -> [Name] -> [Pat]
forall a b. (a -> b) -> [a] -> [b]
map Name -> Pat
VarP [Name]
xs) (Exp -> Body
NormalB (Exp -> Body) -> Exp -> Body
forall a b. (a -> b) -> a -> b
$ [Maybe Exp] -> Exp
TupE ([Maybe Exp] -> Exp) -> [Maybe Exp] -> Exp
forall a b. (a -> b) -> a -> b
$ (Exp -> Maybe Exp) -> [Exp] -> [Maybe Exp]
forall a b. (a -> b) -> [a] -> [b]
map Exp -> Maybe Exp
forall a. a -> Maybe a
Just [Exp]
ys) []]
decomposeTupleT :: TH.Type -> Maybe [TH.Type]
decomposeTupleT :: Type -> Maybe Cxt
decomposeTupleT = Cxt -> Int -> Type -> Maybe Cxt
go [] Int
0
where
go :: [TH.Type] -> Int -> TH.Type -> Maybe [TH.Type]
go :: Cxt -> Int -> Type -> Maybe Cxt
go Cxt
acc !Int
n = \case
TupleT Int
m | Int
m Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
n -> Cxt -> Maybe Cxt
forall a. a -> Maybe a
Just Cxt
acc
Type
f `AppT` Type
a -> Cxt -> Int -> Type -> Maybe Cxt
go (Type
a Type -> Cxt -> Cxt
forall a. a -> [a] -> [a]
: Cxt
acc) (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Type
f
Type
_ -> Maybe Cxt
forall a. Maybe a
Nothing
{-# INLINE decomposeTupleT #-}
newNames :: Int -> String -> Q [Name]
newNames :: Int -> [Char] -> Q [Name]
newNames Int
n [Char]
name = Int -> Q Name -> Q [Name]
forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM Int
n ([Char] -> Q Name
forall (m :: * -> *). Quote m => [Char] -> m Name
newName [Char]
name)
iter :: (Eq t, Num t, Quote m) => t -> m Exp -> m Exp -> m Exp
iter :: forall t (m :: * -> *).
(Eq t, Num t, Quote m) =>
t -> m Exp -> m Exp -> m Exp
iter t
0 m Exp
_ m Exp
e = m Exp
e
iter t
n m Exp
f m Exp
e = t -> m Exp -> m Exp -> m Exp
forall t (m :: * -> *).
(Eq t, Num t, Quote m) =>
t -> m Exp -> m Exp -> m Exp
iter (t
n t -> t -> t
forall a. Num a => a -> a -> a
- t
1) m Exp
f (m Exp
f m Exp -> m Exp -> m Exp
forall (m :: * -> *). Quote m => m Exp -> m Exp -> m Exp
`appE` m Exp
e)