{-# LANGUAGE ScopedTypeVariables #-}
module Data.Singletons.Deriving.Foldable where
import Data.Singletons.Deriving.Infer
import Data.Singletons.Deriving.Util
import Data.Singletons.Names
import Data.Singletons.Syntax
import Language.Haskell.TH.Desugar
mkFoldableInstance :: forall q. DsMonad q => DerivDesc q
mkFoldableInstance mb_ctxt ty dd@(DataDecl _ _ cons) = do
functorLikeValidityChecks False dd
f <- newUniqueName "_f"
z <- newUniqueName "_z"
let ft_foldMap :: FFoldType (q DExp)
ft_foldMap = FT { ft_triv = mkSimpleLam $ \_ -> pure $ DVarE memptyName
, ft_var = pure $ DVarE f
, ft_ty_app = \_ g -> DAppE (DVarE foldMapName) <$> g
, ft_forall = \_ g -> g
, ft_bad_app = error "in other argument in ft_foldMap"
}
ft_foldr :: FFoldType (q DExp)
ft_foldr = FT { ft_triv = mkSimpleLam2 $ \_ z' -> pure z'
, ft_var = pure $ DVarE f
, ft_ty_app = \_ g -> do
gg <- g
mkSimpleLam2 $ \x z' -> pure $
DVarE foldrName `DAppE` gg `DAppE` z' `DAppE` x
, ft_forall = \_ g -> g
, ft_bad_app = error "in other argument in ft_foldr"
}
clause_for_foldMap :: [DPat] -> DCon -> [DExp] -> q DClause
clause_for_foldMap = mkSimpleConClause $ \_ -> mkFoldMap
where
mkFoldMap :: [DExp] -> DExp
mkFoldMap [] = DVarE memptyName
mkFoldMap xs = foldr1 (\x y -> DVarE mappendName `DAppE` x `DAppE` y) xs
clause_for_foldr :: [DPat] -> DCon -> [DExp] -> q DClause
clause_for_foldr = mkSimpleConClause $ \_ -> mkFoldr
where
mkFoldr :: [DExp] -> DExp
mkFoldr = foldr DAppE (DVarE z)
mk_foldMap_clause :: DCon -> q DClause
mk_foldMap_clause con = do
parts <- foldDataConArgs ft_foldMap con
clause_for_foldMap [DVarPa f] con =<< sequence parts
mk_foldr_clause :: DCon -> q DClause
mk_foldr_clause con = do
parts <- foldDataConArgs ft_foldr con
clause_for_foldr [DVarPa f, DVarPa z] con =<< sequence parts
mk_foldMap :: q [DClause]
mk_foldMap =
case cons of
[] -> pure [DClause [DWildPa, DWildPa] (DVarE memptyName)]
_ -> traverse mk_foldMap_clause cons
mk_foldr :: q [DClause]
mk_foldr = traverse mk_foldr_clause cons
foldMap_clauses <- mk_foldMap
foldr_clauses <- mk_foldr
let meths = (foldMapName, UFunction foldMap_clauses)
: case cons of
[] -> []
_ -> [(foldrName, UFunction foldr_clauses)]
constraints <- inferConstraintsDef mb_ctxt (DConPr foldableName) ty cons
return $ InstDecl { id_cxt = constraints
, id_name = foldableName
, id_arg_tys = [ty]
, id_sigs = mempty
, id_meths = meths }