linear-generics-0.1.0.0: tests/Generics/Deriving/Foldable.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeSynonymInstances #-}
#if __GLASGOW_HASKELL__ >= 701
{-# LANGUAGE DefaultSignatures #-}
#endif
#if __GLASGOW_HASKELL__ >= 705
{-# LANGUAGE PolyKinds #-}
#endif
#if __GLASGOW_HASKELL__ >= 710
{-# LANGUAGE Safe #-}
#elif __GLASGOW_HASKELL__ >= 701
{-# LANGUAGE Trustworthy #-}
#endif
module Generics.Deriving.Foldable (
-- * Generic Foldable class
GFoldable(..)
-- * Default method
, gfoldMapdefault
-- * Derived functions
, gtoList
, gconcat
, gconcatMap
, gand
, gor
, gany
, gall
, gsum
, gproduct
, gmaximum
, gmaximumBy
, gminimum
, gminimumBy
, gelem
, gnotElem
, gfind
-- * Internal Foldable class
, GFoldable'(..)
) where
import Control.Applicative (Const, ZipList)
import Data.Maybe
import qualified Data.Monoid as Monoid (First, Last, Product(..), Sum(..))
import Data.Monoid (All(..), Any(..), Dual(..), Endo(..))
#if !(MIN_VERSION_base(4,8,0))
import Data.Monoid (Monoid(..))
#endif
import Generics.Linear
#if MIN_VERSION_base(4,4,0)
import Data.Complex (Complex)
#endif
#if MIN_VERSION_base(4,6,0)
import Data.Ord (Down)
#else
import GHC.Exts (Down)
#endif
#if MIN_VERSION_base(4,7,0)
import Data.Proxy (Proxy)
#endif
#if MIN_VERSION_base(4,8,0)
import Data.Functor.Identity (Identity)
#endif
#if MIN_VERSION_base(4,9,0)
import qualified Data.Functor.Product as Functor (Product)
import qualified Data.Functor.Sum as Functor (Sum)
import Data.Functor.Compose (Compose)
import Data.List.NonEmpty (NonEmpty)
import qualified Data.Semigroup as Semigroup (First, Last)
import Data.Semigroup (Arg, Max, Min, WrappedMonoid)
#endif
--------------------------------------------------------------------------------
-- Generic fold
--------------------------------------------------------------------------------
class GFoldable' t where
gfoldMap' :: Monoid m => (a -> m) -> t a -> m
instance GFoldable' V1 where
gfoldMap' _ _ = mempty
instance GFoldable' U1 where
gfoldMap' _ U1 = mempty
instance GFoldable' Par1 where
gfoldMap' f (Par1 a) = f a
instance GFoldable' (K1 i c) where
gfoldMap' _ (K1 _) = mempty
instance GFoldable' f => GFoldable' (M1 i c f) where
gfoldMap' f (M1 a) = gfoldMap' f a
instance GFoldable' f => GFoldable' (MP1 m f) where
gfoldMap' f (MP1 a) = gfoldMap' f a
instance (GFoldable' f, GFoldable' g) => GFoldable' (f :+: g) where
gfoldMap' f (L1 a) = gfoldMap' f a
gfoldMap' f (R1 a) = gfoldMap' f a
instance (GFoldable' f, GFoldable' g) => GFoldable' (f :*: g) where
gfoldMap' f (a :*: b) = mappend (gfoldMap' f a) (gfoldMap' f b)
instance (GFoldable' f, GFoldable g) => GFoldable' (f :.: g) where
gfoldMap' f (Comp1 x) = gfoldMap' (gfoldMap f) x
instance GFoldable' UAddr where
gfoldMap' _ (UAddr _) = mempty
instance GFoldable' UChar where
gfoldMap' _ (UChar _) = mempty
instance GFoldable' UDouble where
gfoldMap' _ (UDouble _) = mempty
instance GFoldable' UFloat where
gfoldMap' _ (UFloat _) = mempty
instance GFoldable' UInt where
gfoldMap' _ (UInt _) = mempty
instance GFoldable' UWord where
gfoldMap' _ (UWord _) = mempty
class GFoldable t where
gfoldMap :: Monoid m => (a -> m) -> t a -> m
#if __GLASGOW_HASKELL__ >= 701
default gfoldMap :: (Generic1 t, GFoldable' (Rep1 t), Monoid m)
=> (a -> m) -> t a -> m
gfoldMap = gfoldMapdefault
#endif
gfold :: Monoid m => t m -> m
gfold = gfoldMap id
gfoldr :: (a -> b -> b) -> b -> t a -> b
gfoldr f z t = appEndo (gfoldMap (Endo . f) t) z
gfoldr' :: (a -> b -> b) -> b -> t a -> b
gfoldr' f z0 xs = gfoldl f' id xs z0
where f' k x z = k $! f x z
gfoldl :: (a -> b -> a) -> a -> t b -> a
gfoldl f z t = appEndo (getDual (gfoldMap (Dual . Endo . flip f) t)) z
gfoldl' :: (a -> b -> a) -> a -> t b -> a
gfoldl' f z0 xs = gfoldr f' id xs z0
where f' x k z = k $! f z x
gfoldr1 :: (a -> a -> a) -> t a -> a
gfoldr1 f xs = fromMaybe (error "gfoldr1: empty structure")
(gfoldr mf Nothing xs)
where
mf x Nothing = Just x
mf x (Just y) = Just (f x y)
gfoldl1 :: (a -> a -> a) -> t a -> a
gfoldl1 f xs = fromMaybe (error "foldl1: empty structure")
(gfoldl mf Nothing xs)
where
mf Nothing y = Just y
mf (Just x) y = Just (f x y)
gfoldMapdefault :: (Generic1 t, GFoldable' (Rep1 t), Monoid m)
=> (a -> m) -> t a -> m
gfoldMapdefault f x = gfoldMap' f (from1 x)
-- Base types instances
instance GFoldable ((,) a)
instance GFoldable ((,,) a b)
instance GFoldable ((,,,) a b c)
instance GFoldable [] where
gfoldMap = gfoldMapdefault
#if MIN_VERSION_base(4,9,0)
instance GFoldable (Arg a) where
gfoldMap = gfoldMapdefault
#endif
#if MIN_VERSION_base(4,4,0)
instance GFoldable Complex where
gfoldMap = gfoldMapdefault
#endif
instance GFoldable (Const m) where
gfoldMap = gfoldMapdefault
instance GFoldable Down where
gfoldMap = gfoldMapdefault
instance GFoldable Dual where
gfoldMap = gfoldMapdefault
instance GFoldable (Either a) where
gfoldMap = gfoldMapdefault
instance GFoldable Monoid.First where
gfoldMap = gfoldMapdefault
#if MIN_VERSION_base(4,9,0)
instance GFoldable (Semigroup.First) where
gfoldMap = gfoldMapdefault
#endif
#if MIN_VERSION_base(4,8,0)
instance GFoldable Identity where
gfoldMap = gfoldMapdefault
#endif
instance GFoldable Monoid.Last where
gfoldMap = gfoldMapdefault
#if MIN_VERSION_base(4,9,0)
instance GFoldable Semigroup.Last where
gfoldMap = gfoldMapdefault
instance GFoldable Max where
gfoldMap = gfoldMapdefault
#endif
instance GFoldable Maybe where
gfoldMap = gfoldMapdefault
#if MIN_VERSION_base(4,9,0)
instance GFoldable Min where
gfoldMap = gfoldMapdefault
instance GFoldable NonEmpty where
gfoldMap = gfoldMapdefault
#endif
instance GFoldable Monoid.Product where
gfoldMap = gfoldMapdefault
instance (GFoldable f, GFoldable g) => GFoldable (Functor.Product f g)
instance (GFoldable f, GFoldable g) => GFoldable (Compose f g)
#if MIN_VERSION_base(4,7,0)
instance GFoldable Proxy where
gfoldMap = gfoldMapdefault
#endif
instance GFoldable Monoid.Sum where
gfoldMap = gfoldMapdefault
#if MIN_VERSION_base(4,9,0)
instance (GFoldable f, GFoldable g) => GFoldable (Functor.Sum f g) where
gfoldMap = gfoldMapdefault
instance GFoldable WrappedMonoid where
gfoldMap = gfoldMapdefault
#endif
instance GFoldable ZipList where
gfoldMap = gfoldMapdefault
gtoList :: GFoldable t => t a -> [a]
gtoList = gfoldr (:) []
gconcat :: GFoldable t => t [a] -> [a]
gconcat = gfold
gconcatMap :: GFoldable t => (a -> [b]) -> t a -> [b]
gconcatMap = gfoldMap
gand :: GFoldable t => t Bool -> Bool
gand = getAll . gfoldMap All
gor :: GFoldable t => t Bool -> Bool
gor = getAny . gfoldMap Any
gany :: GFoldable t => (a -> Bool) -> t a -> Bool
gany p = getAny . gfoldMap (Any . p)
gall :: GFoldable t => (a -> Bool) -> t a -> Bool
gall p = getAll . gfoldMap (All . p)
gsum :: (GFoldable t, Num a) => t a -> a
gsum = Monoid.getSum . gfoldMap Monoid.Sum
gproduct :: (GFoldable t, Num a) => t a -> a
gproduct = Monoid.getProduct . gfoldMap Monoid.Product
gmaximum :: (GFoldable t, Ord a) => t a -> a
gmaximum = gfoldr1 max
gmaximumBy :: GFoldable t => (a -> a -> Ordering) -> t a -> a
gmaximumBy cmp = gfoldr1 max'
where max' x y = case cmp x y of
GT -> x
_ -> y
gminimum :: (GFoldable t, Ord a) => t a -> a
gminimum = gfoldr1 min
gminimumBy :: GFoldable t => (a -> a -> Ordering) -> t a -> a
gminimumBy cmp = gfoldr1 min'
where min' x y = case cmp x y of
GT -> y
_ -> x
gelem :: (GFoldable t, Eq a) => a -> t a -> Bool
gelem = gany . (==)
gnotElem :: (GFoldable t, Eq a) => a -> t a -> Bool
gnotElem x = not . gelem x
gfind :: GFoldable t => (a -> Bool) -> t a -> Maybe a
gfind p = listToMaybe . gconcatMap (\ x -> if p x then [x] else [])