on develop help sign in
Document DecidablyEmpty and add missing instances
ef51a75John Ericson
ChangeLog.md+2
@@ -4,6 +4,8 @@
4
4
5* Create `PatchMapWithPatchingMove` variant which supports moves with a patch.
5* Create `PatchMapWithPatchingMove` variant which supports moves with a patch.
6
6
7+* Create `DecidablyEmpty` subclass of `Monoid`.
8+
7## 0.0.2.0
9## 0.0.2.0
8
10
9* Consistently provide:
11* Consistently provide:
src/Data/Monoid/DecidablyEmpty.hs+91−2
@@ -1,14 +1,103 @@
1+{-# LANGUAGE CPP #-}
1{-# LANGUAGE DefaultSignatures #-}
2{-# LANGUAGE DefaultSignatures #-}
3+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+{-# LANGUAGE StandaloneDeriving #-}
5+{-# LANGUAGE TypeOperators #-}
2
6
3-- TODO upstream somwhere else?
7-- TODO upstream somwhere else?
4module Data.Monoid.DecidablyEmpty where
8module Data.Monoid.DecidablyEmpty where
5
9
10+import Data.Functor.Identity
11+import Data.Functor.Const
12+import Data.Monoid
13+import Data.Maybe (isNothing)
14+import Data.Ord
6import Data.Proxy
15import Data.Proxy
16+import Data.Semigroup hiding (First, Last)
17+import GHC.Generics
7
18
19+import qualified Data.IntSet as IntSet
20+import qualified Data.IntMap as IntMap
21+import qualified Data.Map as Map
22+import qualified Data.Sequence as Seq
23+import qualified Data.Set as Set
24+
25+import Data.GADT.Compare
26+import qualified Data.Dependent.Map as DMap
27+
28+-- | A 'DecidablyEmpty' is one where it can be computed whether or not an
29+-- arbitrary value is 'mempty'.
30+--
31+-- By using this class rather than 'Eq', we avoid unnecessary constraining the
32+-- contents of 'Functor's. This makes it possible to efficiently combine and/or
33+-- nest patch maps with 'Eq'-lacking values (e.g. functions) at the leaves.
8class Monoid a => DecidablyEmpty a where
34class Monoid a => DecidablyEmpty a where
9 isEmpty :: a -> Bool
35 isEmpty :: a -> Bool
10 default isEmpty :: Eq a => a -> Bool
36 default isEmpty :: Eq a => a -> Bool
11 isEmpty = (==) mempty
37 isEmpty = (==) mempty
12
38
39+-- base
40+
41+instance DecidablyEmpty Ordering
13−instance DecidablyEmpty (Proxy a) where
42+instance DecidablyEmpty ()
43+instance DecidablyEmpty Any
44+instance DecidablyEmpty All
45+-- instance DecidablyEmpty Lifetime
46+-- instance DecidablyEmpty Event
47+instance DecidablyEmpty [a] where
48+ isEmpty = null
49+instance Semigroup a => DecidablyEmpty (Maybe a) where
14− isEmpty ~Proxy = True
50+ isEmpty = isNothing
51+#if MIN_VERSION_base(4,11,0)
52+deriving instance DecidablyEmpty a => DecidablyEmpty (Down a)
53+#endif
54+deriving instance (Num a, DecidablyEmpty a) => DecidablyEmpty (Product a)
55+deriving instance (DecidablyEmpty a, Num a) => DecidablyEmpty (Sum a)
56+deriving instance DecidablyEmpty a => DecidablyEmpty (Dual a)
57+deriving instance Semigroup a => DecidablyEmpty (First a)
58+deriving instance Semigroup a => DecidablyEmpty (Last a)
59+deriving instance DecidablyEmpty a => DecidablyEmpty (Identity a)
60+deriving instance Semigroup a => DecidablyEmpty (Option a)
61+deriving instance DecidablyEmpty m => DecidablyEmpty (WrappedMonoid m)
62+instance (Ord a, Bounded a) => DecidablyEmpty (Max a)
63+instance (Ord a, Bounded a) => DecidablyEmpty (Min a)
64+instance DecidablyEmpty (U1 p)
65+instance DecidablyEmpty (Proxy s)
66+#if MIN_VERSION_base(4,12,0)
67+deriving instance DecidablyEmpty (f p) => DecidablyEmpty (Rec1 f p)
68+#endif
69+deriving instance DecidablyEmpty a => DecidablyEmpty (Const a b)
70+deriving instance DecidablyEmpty c => DecidablyEmpty (K1 i c p)
71+instance (DecidablyEmpty (f p), DecidablyEmpty (g p)) => DecidablyEmpty ((f :*: g) p) where
72+ isEmpty (x :*: y) = isEmpty x && isEmpty y
73+#if MIN_VERSION_base(4,12,0)
74+deriving instance DecidablyEmpty (f p) => DecidablyEmpty (M1 i c f p)
75+deriving instance DecidablyEmpty (f (g p)) => DecidablyEmpty ((f :.: g) p)
76+#endif
77+
78+instance (DecidablyEmpty a, DecidablyEmpty b) => DecidablyEmpty (a, b) where
79+ isEmpty (a, b) = isEmpty a && isEmpty b
80+instance (DecidablyEmpty a, DecidablyEmpty b, DecidablyEmpty c) => DecidablyEmpty (a, b, c) where
81+ isEmpty (a, b, c) = isEmpty a && isEmpty b && isEmpty c
82+instance (DecidablyEmpty a, DecidablyEmpty b, DecidablyEmpty c, DecidablyEmpty d) => DecidablyEmpty (a, b, c, d) where
83+ isEmpty (a, b, c, d) = isEmpty a && isEmpty b && isEmpty c && isEmpty d
84+instance (DecidablyEmpty a, DecidablyEmpty b, DecidablyEmpty c, DecidablyEmpty d, DecidablyEmpty e) => DecidablyEmpty (a, b, c, d, e) where
85+ isEmpty (a, b, c, d, e) = isEmpty a && isEmpty b && isEmpty c && isEmpty d && isEmpty e
86+
87+-- containers
88+
89+instance DecidablyEmpty IntSet.IntSet where
90+ isEmpty = IntSet.null
91+instance DecidablyEmpty (IntMap.IntMap v) where
92+ isEmpty = IntMap.null
93+instance Ord k => DecidablyEmpty (Map.Map k v) where
94+ isEmpty = Map.null
95+instance DecidablyEmpty (Seq.Seq v) where
96+ isEmpty = Seq.null
97+instance Ord k => DecidablyEmpty (Set.Set k) where
98+ isEmpty = Set.null
99+
100+-- dependent-map
101+
102+instance GCompare k => DecidablyEmpty (DMap.DMap k v) where
103+ isEmpty = DMap.null
src/Data/Patch/DMap.hs+6
@@ -5,6 +5,7 @@
5{-# LANGUAGE ScopedTypeVariables #-}
5{-# LANGUAGE ScopedTypeVariables #-}
6{-# LANGUAGE StandaloneDeriving #-}
6{-# LANGUAGE StandaloneDeriving #-}
7{-# LANGUAGE TypeFamilies #-}
7{-# LANGUAGE TypeFamilies #-}
8+
8-- | 'Patch'es on 'DMap' that consist only of insertions (or overwrites) and deletions.
9-- | 'Patch'es on 'DMap' that consist only of insertions (or overwrites) and deletions.
9module Data.Patch.DMap where
10module Data.Patch.DMap where
10
11
@@ -18,6 +19,7 @@ import Data.Functor.Constant
18import Data.Functor.Misc
19import Data.Functor.Misc
19import qualified Data.IntMap as IntMap
20import qualified Data.IntMap as IntMap
20import qualified Data.Map as Map
21import qualified Data.Map as Map
22+import Data.Monoid.DecidablyEmpty
21import Data.Semigroup (Semigroup (..))
23import Data.Semigroup (Semigroup (..))
22import Data.Some (Some)
24import Data.Some (Some)
23
25
@@ -30,6 +32,10 @@ deriving instance GCompare k => Semigroup (PatchDMap k v)
30
32
31deriving instance GCompare k => Monoid (PatchDMap k v)
33deriving instance GCompare k => Monoid (PatchDMap k v)
32
34
35+-- It won't let me derive for some reason
36+instance GCompare k => DecidablyEmpty (PatchDMap k v) where
37+ isEmpty (PatchDMap m) = DMap.null m
38+
33-- | Apply the insertions or deletions to a given 'DMap'.
39-- | Apply the insertions or deletions to a given 'DMap'.
34instance GCompare k => Patch (PatchDMap k v) where
40instance GCompare k => Patch (PatchDMap k v) where
35 type PatchTarget (PatchDMap k v) = DMap k v
41 type PatchTarget (PatchDMap k v) = DMap k v
src/Data/Patch/DMapWithMove.hs+5
@@ -29,6 +29,7 @@ import Data.GADT.Compare (GEq (..))
29import Data.GADT.Show (GShow, gshow)
29import Data.GADT.Show (GShow, gshow)
30import qualified Data.Map as Map
30import qualified Data.Map as Map
31import Data.Maybe
31import Data.Maybe
32+import Data.Monoid.DecidablyEmpty
32import Data.Semigroup (Semigroup (..), (<>))
33import Data.Semigroup (Semigroup (..), (<>))
33import Data.Some (Some(Some))
34import Data.Some (Some(Some))
34import Data.These
35import Data.These
@@ -42,6 +43,10 @@ import Data.These
42-- * A move should always be represented with both the destination key (as a 'From_Move') and the source key (as a @'ComposeMaybe' ('Just' destination)@)
43-- * A move should always be represented with both the destination key (as a 'From_Move') and the source key (as a @'ComposeMaybe' ('Just' destination)@)
43newtype PatchDMapWithMove k v = PatchDMapWithMove (DMap k (NodeInfo k v))
44newtype PatchDMapWithMove k v = PatchDMapWithMove (DMap k (NodeInfo k v))
44
45
46+-- It won't let me derive for some reason
47+instance GCompare k => DecidablyEmpty (PatchDMapWithMove k v) where
48+ isEmpty (PatchDMapWithMove m) = DMap.null m
49+
45-- |Structure which represents what changes apply to a particular key. @_nodeInfo_from@ specifies what happens to this key, and in particular what other key
50-- |Structure which represents what changes apply to a particular key. @_nodeInfo_from@ specifies what happens to this key, and in particular what other key
46-- the current key is moving from, while @_nodeInfo_to@ specifies what key the current key is moving to if involved in a move.
51-- the current key is moving from, while @_nodeInfo_to@ specifies what key the current key is moving to if involved in a move.
47data NodeInfo k v a = NodeInfo
52data NodeInfo k v a = NodeInfo
src/Data/Patch/IntMap.hs+9−6
@@ -1,7 +1,9 @@
1+{-# LANGUAGE CPP #-}
1{-# LANGUAGE DeriveTraversable #-}
2{-# LANGUAGE DeriveTraversable #-}
2{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
6+{-# LANGUAGE StandaloneDeriving #-}
5{-# LANGUAGE TemplateHaskell #-}
7{-# LANGUAGE TemplateHaskell #-}
6{-# LANGUAGE TypeFamilies #-}
8{-# LANGUAGE TypeFamilies #-}
7
9
@@ -13,7 +15,10 @@ import Control.Lens
13import Data.IntMap.Strict (IntMap)
15import Data.IntMap.Strict (IntMap)
14import qualified Data.IntMap.Strict as IntMap
16import qualified Data.IntMap.Strict as IntMap
15import Data.Maybe
17import Data.Maybe
16−import Data.Semigroup
18+import Data.Monoid.DecidablyEmpty
19+#if !MIN_VERSION_base(4,10,0)
20+import Data.Semigroup (Semigroup (..))
21+#endif
17import Data.Patch.Class
22import Data.Patch.Class
18
23
19-- | 'Patch' for 'IntMap' which represents insertion or deletion of keys in the mapping.
24-- | 'Patch' for 'IntMap' which represents insertion or deletion of keys in the mapping.
@@ -21,16 +26,14 @@ import Data.Patch.Class
21-- and @Nothing@ means delete.
26-- and @Nothing@ means delete.
22newtype PatchIntMap a = PatchIntMap { unPatchIntMap :: IntMap (Maybe a) }
27newtype PatchIntMap a = PatchIntMap { unPatchIntMap :: IntMap (Maybe a) }
23 deriving ( Show, Read, Eq, Ord
28 deriving ( Show, Read, Eq, Ord
24− , Functor, Foldable, Traversable, Monoid
29+ , Functor, Foldable, Traversable
30+ , Monoid, DecidablyEmpty
25 )
31 )
26
32
27-- | @a <> b@ will apply the changes of @b@ and then apply the changes of @a@.
33-- | @a <> b@ will apply the changes of @b@ and then apply the changes of @a@.
28-- If the same key is modified by both patches, the one on the left will take
34-- If the same key is modified by both patches, the one on the left will take
29-- precedence.
35-- precedence.
30−instance Semigroup (PatchIntMap v) where
36+deriving instance Semigroup (PatchIntMap v)
31− PatchIntMap a <> PatchIntMap b = PatchIntMap $ a `mappend` b --TODO: Add a semigroup instance for Map
32− -- PatchMap is idempotent, so stimes n is id for every n
33− stimes = stimesIdempotentMonoid
34
37
35makeWrapped ''PatchIntMap
38makeWrapped ''PatchIntMap
36
39
src/Data/Patch/Map.hs+7−7
@@ -1,5 +1,6 @@
1{-# LANGUAGE DeriveTraversable #-}
1{-# LANGUAGE DeriveTraversable #-}
2{-# LANGUAGE FlexibleInstances #-}
2{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3{-# LANGUAGE LambdaCase #-}
4{-# LANGUAGE LambdaCase #-}
4{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE StandaloneDeriving #-}
6{-# LANGUAGE StandaloneDeriving #-}
@@ -16,6 +17,7 @@ import Control.Lens
16import Data.Map (Map)
17import Data.Map (Map)
17import qualified Data.Map as Map
18import qualified Data.Map as Map
18import Data.Maybe
19import Data.Maybe
20+import Data.Monoid.DecidablyEmpty
19import Data.Semigroup
21import Data.Semigroup
20
22
21-- | A set of changes to a 'Map'. Any element may be inserted/updated or
23-- | A set of changes to a 'Map'. Any element may be inserted/updated or
@@ -24,11 +26,14 @@ import Data.Semigroup
24newtype PatchMap k v = PatchMap { unPatchMap :: Map k (Maybe v) }
26newtype PatchMap k v = PatchMap { unPatchMap :: Map k (Maybe v) }
25 deriving ( Show, Read, Eq, Ord
27 deriving ( Show, Read, Eq, Ord
26 , Foldable, Traversable
28 , Foldable, Traversable
29+ , DecidablyEmpty
27 )
30 )
28
31
29-- | 'fmap'ping a 'PatchMap' will alter all of the values it will insert.
32-- | 'fmap'ping a 'PatchMap' will alter all of the values it will insert.
30-- Deletions are unaffected.
33-- Deletions are unaffected.
31deriving instance Functor (PatchMap k)
34deriving instance Functor (PatchMap k)
35+-- | The empty 'PatchMap' contains no insertions or deletions
36+deriving instance Ord k => Monoid (PatchMap k v)
32
37
33-- | @a <> b@ will apply the changes of @b@ and then apply the changes of @a@.
38-- | @a <> b@ will apply the changes of @b@ and then apply the changes of @a@.
34-- If the same key is modified by both patches, the one on the left will take
39-- If the same key is modified by both patches, the one on the left will take
@@ -38,8 +43,6 @@ instance Ord k => Semigroup (PatchMap k v) where
38 -- PatchMap is idempotent, so stimes n is id for every n
43 -- PatchMap is idempotent, so stimes n is id for every n
39 stimes = stimesIdempotentMonoid
44 stimes = stimesIdempotentMonoid
40
45
41−makeWrapped ''PatchMap
42−
43-- | Apply the insertions or deletions to a given 'Map'.
46-- | Apply the insertions or deletions to a given 'Map'.
44instance Ord k => Patch (PatchMap k v) where
47instance Ord k => Patch (PatchMap k v) where
45 type PatchTarget (PatchMap k v) = Map k v
48 type PatchTarget (PatchMap k v) = Map k v
@@ -57,11 +60,6 @@ instance TraversableWithIndex k (PatchMap k) where
57 itraverse = itraversed . Indexed
60 itraverse = itraversed . Indexed
58 itraversed = _Wrapped .> itraversed <. traversed
61 itraversed = _Wrapped .> itraversed <. traversed
59
62
60−-- | The empty 'PatchMap' contains no insertions or deletions
61−instance Ord k => Monoid (PatchMap k v) where
62− mempty = PatchMap mempty
63− mappend = (<>)
64−
65-- | Returns all the new elements that will be added to the 'Map'
63-- | Returns all the new elements that will be added to the 'Map'
66patchMapNewElements :: PatchMap k v -> [v]
64patchMapNewElements :: PatchMap k v -> [v]
67patchMapNewElements (PatchMap p) = catMaybes $ Map.elems p
65patchMapNewElements (PatchMap p) = catMaybes $ Map.elems p
@@ -69,3 +67,5 @@ patchMapNewElements (PatchMap p) = catMaybes $ Map.elems p
69-- | Returns all the new elements that will be added to the 'Map'
67-- | Returns all the new elements that will be added to the 'Map'
70patchMapNewElementsMap :: PatchMap k v -> Map k v
68patchMapNewElementsMap :: PatchMap k v -> Map k v
71patchMapNewElementsMap (PatchMap p) = Map.mapMaybe id p
69patchMapNewElementsMap (PatchMap p) = Map.mapMaybe id p
70+
71+makeWrapped ''PatchMap
src/Data/Patch/MapWithPatchingMove.hs+2
@@ -1,4 +1,5 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE LambdaCase #-}
5{-# LANGUAGE LambdaCase #-}
@@ -45,6 +46,7 @@ deriving instance (Show k, Show p, Show (PatchTarget p)) => Show (PatchMapWithPa
45deriving instance (Ord k, Read k, Read p, Read (PatchTarget p)) => Read (PatchMapWithPatchingMove k p)
46deriving instance (Ord k, Read k, Read p, Read (PatchTarget p)) => Read (PatchMapWithPatchingMove k p)
46deriving instance (Eq k, Eq p, Eq (PatchTarget p)) => Eq (PatchMapWithPatchingMove k p)
47deriving instance (Eq k, Eq p, Eq (PatchTarget p)) => Eq (PatchMapWithPatchingMove k p)
47deriving instance (Ord k, Ord p, Ord (PatchTarget p)) => Ord (PatchMapWithPatchingMove k p)
48deriving instance (Ord k, Ord p, Ord (PatchTarget p)) => Ord (PatchMapWithPatchingMove k p)
49+deriving instance (Ord k, Monoid p, DecidablyEmpty p, Patch p) => DecidablyEmpty (PatchMapWithPatchingMove k p)
48
50
49-- | Holds the information about each key: where its new value should come from,
51-- | Holds the information about each key: where its new value should come from,
50-- and where its old value should go to
52-- and where its old value should go to