{-# LANGUAGE CPP #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeOperators #-}

-- TODO upstream somwhere else?
module Data.Monoid.DecidablyEmpty where

import Data.Functor.Identity
import Data.Functor.Const
import Data.Monoid
import Data.Maybe (isNothing)
#if MIN_VERSION_base(4,11,0)
import Data.Ord
#endif
import Data.Proxy
import Data.Semigroup hiding (First, Last)
#if MIN_VERSION_base(4,12,0)
import GHC.Generics
#endif

import qualified Data.IntSet as IntSet
import qualified Data.IntMap as IntMap
import qualified Data.Map as Map
import qualified Data.Sequence as Seq
import qualified Data.Set as Set

import Data.GADT.Compare
import qualified Data.Dependent.Map as DMap

-- | A 'DecidablyEmpty' is one where it can be computed whether or not an
-- arbitrary value is 'mempty'.
--
-- By using this class rather than 'Eq', we avoid unnecessary constraining the
-- contents of 'Functor's. This makes it possible to efficiently combine and/or
-- nest patch maps with 'Eq'-lacking values (e.g. functions) at the leaves.
class Monoid a => DecidablyEmpty a where
  isEmpty :: a -> Bool
  default isEmpty :: Eq a => a -> Bool
  isEmpty = a -> a -> Bool
forall a. Eq a => a -> a -> Bool
(==) a
forall a. Monoid a => a
mempty

-- base

instance DecidablyEmpty Ordering
instance DecidablyEmpty ()
instance DecidablyEmpty Any
instance DecidablyEmpty All
-- instance DecidablyEmpty Lifetime
-- instance DecidablyEmpty Event
instance DecidablyEmpty [a] where
  isEmpty :: [a] -> Bool
isEmpty = [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null
instance
#if MIN_VERSION_base(4,11,0)
  Semigroup a
#else
  Monoid a
#endif
  => DecidablyEmpty (Maybe a) where
  isEmpty :: Maybe a -> Bool
isEmpty = Maybe a -> Bool
forall a. Maybe a -> Bool
isNothing
deriving instance (Num a, DecidablyEmpty a) => DecidablyEmpty (Product a)
deriving instance (DecidablyEmpty a, Num a) => DecidablyEmpty (Sum a)
deriving instance DecidablyEmpty a => DecidablyEmpty (Dual a)
instance DecidablyEmpty (First a) where
  isEmpty :: First a -> Bool
isEmpty (First Maybe a
a) = Maybe a -> Bool
forall a. Maybe a -> Bool
isNothing Maybe a
a
instance DecidablyEmpty (Last a) where
  isEmpty :: Last a -> Bool
isEmpty (Last Maybe a
a) = Maybe a -> Bool
forall a. Maybe a -> Bool
isNothing Maybe a
a
deriving instance DecidablyEmpty a => DecidablyEmpty (Identity a)
instance Semigroup a => DecidablyEmpty (Option a) where
  isEmpty :: Option a -> Bool
isEmpty (Option Maybe a
a) = Maybe a -> Bool
forall a. Maybe a -> Bool
isNothing Maybe a
a
deriving instance DecidablyEmpty m => DecidablyEmpty (WrappedMonoid m)
instance (Ord a, Bounded a) => DecidablyEmpty (Max a)
instance (Ord a, Bounded a) => DecidablyEmpty (Min a)
instance DecidablyEmpty (Proxy s)
deriving instance DecidablyEmpty a => DecidablyEmpty (Const a b)
#if MIN_VERSION_base(4,11,0)
deriving instance DecidablyEmpty a => DecidablyEmpty (Down a)
#endif
#if MIN_VERSION_base(4,12,0)
deriving instance DecidablyEmpty p => DecidablyEmpty (Par1 p)
instance DecidablyEmpty (U1 p)
deriving instance DecidablyEmpty (f p) => DecidablyEmpty (Rec1 f p)
deriving instance DecidablyEmpty (f p) => DecidablyEmpty (M1 i c f p)
deriving instance DecidablyEmpty c => DecidablyEmpty (K1 i c p)
instance (DecidablyEmpty (f p), DecidablyEmpty (g p)) => DecidablyEmpty ((f :*: g) p) where
  isEmpty :: (:*:) f g p -> Bool
isEmpty (f p
x :*: g p
y) = f p -> Bool
forall a. DecidablyEmpty a => a -> Bool
isEmpty f p
x Bool -> Bool -> Bool
&& g p -> Bool
forall a. DecidablyEmpty a => a -> Bool
isEmpty g p
y
deriving instance DecidablyEmpty (f (g p)) => DecidablyEmpty ((f :.: g) p)
#endif

instance (DecidablyEmpty a, DecidablyEmpty b) => DecidablyEmpty (a, b) where
  isEmpty :: (a, b) -> Bool
isEmpty (a
a, b
b) = a -> Bool
forall a. DecidablyEmpty a => a -> Bool
isEmpty a
a Bool -> Bool -> Bool
&& b -> Bool
forall a. DecidablyEmpty a => a -> Bool
isEmpty b
b
instance (DecidablyEmpty a, DecidablyEmpty b, DecidablyEmpty c) => DecidablyEmpty (a, b, c) where
  isEmpty :: (a, b, c) -> Bool
isEmpty (a
a, b
b, c
c) = a -> Bool
forall a. DecidablyEmpty a => a -> Bool
isEmpty a
a Bool -> Bool -> Bool
&& b -> Bool
forall a. DecidablyEmpty a => a -> Bool
isEmpty b
b Bool -> Bool -> Bool
&& c -> Bool
forall a. DecidablyEmpty a => a -> Bool
isEmpty c
c
instance (DecidablyEmpty a, DecidablyEmpty b, DecidablyEmpty c, DecidablyEmpty d) => DecidablyEmpty (a, b, c, d) where
  isEmpty :: (a, b, c, d) -> Bool
isEmpty (a
a, b
b, c
c, d
d) = a -> Bool
forall a. DecidablyEmpty a => a -> Bool
isEmpty a
a Bool -> Bool -> Bool
&& b -> Bool
forall a. DecidablyEmpty a => a -> Bool
isEmpty b
b Bool -> Bool -> Bool
&& c -> Bool
forall a. DecidablyEmpty a => a -> Bool
isEmpty c
c Bool -> Bool -> Bool
&& d -> Bool
forall a. DecidablyEmpty a => a -> Bool
isEmpty d
d
instance (DecidablyEmpty a, DecidablyEmpty b, DecidablyEmpty c, DecidablyEmpty d, DecidablyEmpty e) => DecidablyEmpty (a, b, c, d, e) where
  isEmpty :: (a, b, c, d, e) -> Bool
isEmpty (a
a, b
b, c
c, d
d, e
e) = a -> Bool
forall a. DecidablyEmpty a => a -> Bool
isEmpty a
a Bool -> Bool -> Bool
&& b -> Bool
forall a. DecidablyEmpty a => a -> Bool
isEmpty b
b Bool -> Bool -> Bool
&& c -> Bool
forall a. DecidablyEmpty a => a -> Bool
isEmpty c
c Bool -> Bool -> Bool
&& d -> Bool
forall a. DecidablyEmpty a => a -> Bool
isEmpty d
d Bool -> Bool -> Bool
&& e -> Bool
forall a. DecidablyEmpty a => a -> Bool
isEmpty e
e

-- containers

instance DecidablyEmpty IntSet.IntSet where
  isEmpty :: IntSet -> Bool
isEmpty = IntSet -> Bool
IntSet.null
instance DecidablyEmpty (IntMap.IntMap v) where
  isEmpty :: IntMap v -> Bool
isEmpty = IntMap v -> Bool
forall v. IntMap v -> Bool
IntMap.null
instance Ord k => DecidablyEmpty (Map.Map k v) where
  isEmpty :: Map k v -> Bool
isEmpty = Map k v -> Bool
forall k a. Map k a -> Bool
Map.null
instance DecidablyEmpty (Seq.Seq v) where
  isEmpty :: Seq v -> Bool
isEmpty = Seq v -> Bool
forall v. Seq v -> Bool
Seq.null
instance Ord k => DecidablyEmpty (Set.Set k) where
  isEmpty :: Set k -> Bool
isEmpty = Set k -> Bool
forall a. Set a -> Bool
Set.null

-- dependent-map

instance GCompare k => DecidablyEmpty (DMap.DMap k v) where
  isEmpty :: DMap k v -> Bool
isEmpty = DMap k v -> Bool
forall k1 (k2 :: k1 -> *) (f :: k1 -> *). DMap k2 f -> Bool
DMap.null