module Generics.EMGM.Derive.EP (
#ifndef __HADDOCK__
mkEP,
#endif
) where
#ifndef __HADDOCK__
import Language.Haskell.TH
import Generics.EMGM.Common.Representation
import Generics.EMGM.Derive.Common
appN :: (a -> b) -> (b -> b) -> Int -> a -> b
appN fz _ 0 x = fz x
appN fz fn n x = fn (appN fz fn (n 1) x)
conProd :: a -> (a -> a -> a) -> (Name -> a) -> NCon -> a
conProd unit prod var = namesRep . cvars
where
namesRep = productize unit id prod . map var
repsSums :: (Name -> a -> a) -> [a] -> [a]
repsSums mkSum = listCase3 [] (:[]) more
where
inL = mkSum 'L
inR = mkSum 'R
more x xs = inL x : appLR 1 xs
appLR n (y:[]) = [appN inR inR (n 1) y]
appLR n (y:ys) = appN inL inR n y : appLR (n + 1) ys
appLR _ _ = error "repsSums: Should not be here!"
consReps :: a -> (a -> a -> a) -> (Name -> a) -> (Name -> a -> a) -> [NCon] -> [a]
consReps unit prod var sum_ = repsSums sum_ . prods
where
prods = map (conProd unit prod var)
consClauses :: (a -> [Pat]) -> (a -> [Exp]) -> a -> [Clause]
consClauses mkPats mkExps cons = zipWith mkClause (mkPats cons) (mkExps cons)
where
mkClause p e = Clause [p] (NormalB e) []
fromClauses, toClauses :: [NCon] -> [Clause]
fromClauses = consClauses (map dataP) (consReps unitE prodE VarE sumE)
toClauses = consClauses (consReps unitP prodP VarP sumP) (map (dataE id))
mkFunD :: ([NCon] -> [Clause]) -> DT -> Name -> Dec
mkFunD mkClauses dt funNm = FunD funNm (mkClauses (ncons dt))
mkEpSig :: DT -> Name -> Dec
mkEpSig dt ep = SigD ep typ
where
vars = tvars dt
typ = ForallT vars [] (AppT (AppT (ConT ''EP) rtyp) styp)
rtyp = foldl AppT (ConT (tname dt)) . map VarT $ vars
mkSum = AppT . AppT (ConT ''(:+:))
mkProd = AppT . AppT (ConT ''(:*:))
unit = ConT ''Unit
styp = mkSopDT id unit mkSum mkProd (flip const) dt
mkEP :: Modifiers -> DT -> Name -> Name -> (Name, [Dec])
mkEP mods dt fromName toName = (epName, [epSig, epDec])
where
typeName = tname dt
maybeTypeStr = toMaybeString $ lookup (nameBase typeName) mods
epName = mkFunName "ep" maybeTypeStr typeName ""
fromDec = mkFunD fromClauses dt fromName
toDec = mkFunD toClauses dt toName
body = AppE (AppE (ConE 'EP) (VarE fromName)) (VarE toName)
epSig = mkEpSig dt epName
epDec = ValD (VarP epName) (NormalB body) [fromDec, toDec]
#endif