{-# LANGUAGE ScopedTypeVariables #-} ----------------------------------------------------------------------------- -- | -- Module : Data.Singletons.Deriving.Foldable -- Copyright : (C) 2018 Ryan Scott -- License : BSD-style (see LICENSE) -- Maintainer : Ryan Scott -- Stability : experimental -- Portability : non-portable -- -- Implements deriving of Foldable instances -- ---------------------------------------------------------------------------- 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 -- foldMap f = \x -> mempty , ft_var = pure $ DVarE f -- foldMap f = f , ft_ty_app = \_ g -> DAppE (DVarE foldMapName) <$> g -- foldMap f = foldMap 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' -- foldr f = \x z -> z , ft_var = pure $ DVarE f -- foldr f = f , ft_ty_app = \_ g -> do gg <- g mkSimpleLam2 $ \x z' -> pure $ DVarE foldrName `DAppE` gg `DAppE` z' `DAppE` x -- foldr f = (\x z -> foldr g z 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 -- mappend v1 (mappend v2 ..) 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 -- g1 v1 (g2 v2 (.. z)) 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 }