1{-# LANGUAGE DeriveTraversable #-}
2{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE TemplateHaskell #-}
6{-# LANGUAGE TypeFamilies #-}
8-- | Module containing 'PatchIntMap', a 'Patch' for 'IntMap' which allows for
9-- insert/update or delete of associations.
10module Data.Patch.IntMap where
13import Data.IntMap.Strict (IntMap)
14import qualified Data.IntMap.Strict as IntMap
17import Data.Patch.Class
19-- | 'Patch' for 'IntMap' which represents insertion or deletion of keys in the mapping.
20-- Internally represented by 'IntMap (Maybe a)', where @Just@ means insert/update
21-- and @Nothing@ means delete.
22newtype PatchIntMap a = PatchIntMap { unPatchIntMap :: IntMap (Maybe a) }
23 deriving ( Show, Read, Eq, Ord
24 , Functor, Foldable, Traversable, Monoid
27-- | @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
30instance Semigroup (PatchIntMap v) where
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
35makeWrapped ''PatchIntMap
37-- | Apply the insertions or deletions to a given 'IntMap'.
38instance Patch (PatchIntMap a) where
39 type PatchTarget (PatchIntMap a) = IntMap a
40 apply (PatchIntMap p) v = if IntMap.null p then Nothing else Just $
41 let removes = IntMap.filter isNothing p
42 adds = IntMap.mapMaybe id p
43 in IntMap.union adds $ v `IntMap.difference` removes
45instance FunctorWithIndex Int PatchIntMap
46instance FoldableWithIndex Int PatchIntMap
47instance TraversableWithIndex Int PatchIntMap where
48 itraverse = itraversed . Indexed
49 itraversed = _Wrapped .> itraversed <. traversed
51-- | Map a function @Int -> a -> b@ over all @a@s in the given @'PatchIntMap' a@
52-- (that is, all inserts/updates), producing a @PatchIntMap b@.
53mapIntMapPatchWithKey :: (Int -> a -> b) -> PatchIntMap a -> PatchIntMap b
54mapIntMapPatchWithKey f (PatchIntMap m) = PatchIntMap $ IntMap.mapWithKey (\ k mv -> f k <$> mv) m
56-- | Map an effectful function @Int -> a -> f b@ over all @a@s in the given @'PatchIntMap' a@
57-- (that is, all inserts/updates), producing a @f (PatchIntMap b)@.
58traverseIntMapPatchWithKey :: Applicative f => (Int -> a -> f b) -> PatchIntMap a -> f (PatchIntMap b)
59traverseIntMapPatchWithKey f (PatchIntMap m) = PatchIntMap <$> IntMap.traverseWithKey (\k mv -> traverse (f k) mv) m
61-- | Extract all @a@s inserted/updated by the given @'PatchIntMap' a@.
62patchIntMapNewElements :: PatchIntMap a -> [a]
63patchIntMapNewElements (PatchIntMap m) = catMaybes $ IntMap.elems m
65-- | Convert the given @'PatchIntMap' a@ into an @'IntMap' a@ with all
66-- the inserts/updates in the given patch.
67patchIntMapNewElementsMap :: PatchIntMap a -> IntMap a
68patchIntMapNewElementsMap (PatchIntMap m) = IntMap.mapMaybe id m
70-- | Subset the given @'IntMap' a@ to contain only the keys that would be
71-- deleted by the given @'PatchIntMap' a@.
72getDeletions :: PatchIntMap v -> IntMap v' -> IntMap v'
73getDeletions (PatchIntMap m) v = IntMap.intersection v m
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list