on develop help sign in
Merge pull request #12 from reflex-frp/add-WithIndex-instances

Add *WithIndex instances

commitda266c5cfa44717f383b45cc097ed706f35825ad authorJohn Ericson <John.Ericson@Obsidian.Systems> dateFri 17 Jan 2020, 15:20 (7 years ago) parenteb6b6e5c6216d3
8 files changed+114−48
ChangeLog.md+12 dep/reflex-platform/default.nix+7−6 dep/reflex-platform/github.json+3−2 patch.cabal+1 release.nix+20−10 src/Data/Patch/IntMap.hs+23−10 src/Data/Patch/Map.hs+28−13 src/Data/Patch/MapWithMove.hs+20−7
ChangeLog.md+12
@@ -1,5 +1,17 @@
11# Revision history for patch
22
3+## Unreleased
4+
5+* Consistently provide:
6+
7+ - `Wrapped` instances
8+
9+ - `*WithIndex` instances
10+
11+ - `un*` newtype unwrappers
12+
13+ for `PatchMap`, `PatchIntMap`, and `PatchMapWithMove`.
14+
315## 0.0.1.0
416
517* Support older GHCs with `split-these` flag.
dep/reflex-platform/default.nix+7−6
@@ -1,7 +1,8 @@
11# DO NOT HAND-EDIT THIS FILE
2−import ((import <nixpkgs> {}).fetchFromGitHub (
3− let json = builtins.fromJSON (builtins.readFile ./github.json);
4− in { inherit (json) owner repo rev sha256;
5− private = json.private or false;
6− }
7−))
2+let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }:
3+ if !fetchSubmodules && !private then builtins.fetchTarball {
4+ url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256;
5+ } else (import <nixpkgs> {}).fetchFromGitHub {
6+ inherit owner repo rev sha256 fetchSubmodules private;
7+ };
8+in import (fetch (builtins.fromJSON (builtins.readFile ./github.json)))
dep/reflex-platform/github.json+3−2
@@ -2,6 +2,7 @@
22 "owner": "reflex-frp",
33 "repo": "reflex-platform",
44 "branch": "master",
5− "rev": "510b990d0b11f0626afbec5fe8575b5b2395391b",
6− "sha256": "09cmahsbxr0963wq171c7j139iyzz49hramr4v9nsf684wcwkngv"
5+ "private": false,
6+ "rev": "c9d11db1b98855fe8ab24a3ff6a5dbe0ad902ad9",
7+ "sha256": "0sfzkqdvyah5mwvmli0wq1nl0b8cvk2cmfgfy4rz57wv42x3099y"
78}
patch.cabal+1
@@ -35,6 +35,7 @@ library
3535 , containers >= 0.6 && < 0.7
3636 , dependent-map >= 0.3 && < 0.4
3737 , dependent-sum >= 0.6 && < 0.7
38+ , lens >= 4.7 && < 5
3839 , semigroupoids >= 4.0 && < 6
3940 , transformers >= 0.5.6.0 && < 0.6
4041 , witherable >= 0.3 && < 0.3.2
release.nix+20−10
@@ -18,16 +18,26 @@ let
1818 "ghcIosAarch64"
1919 ];
2020 compilerPkgs = lib.genAttrs compilers (ghc: let
21− src = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [
22− "release.nix"
23− ".git"
24− "dist"
25− "dist-newstyle"
26− "cabal.haskell-ci"
27− "cabal.project"
28− ".travis.yml"
29− ])) ./.;
30− in reflex-platform.${ghc}.callCabal2nix "patch" src {});
21+ reflex-platform = reflex-platform-fun {
22+ inherit system;
23+ haskellOverlays = [
24+ # Use this package's source for reflex
25+ (self: super: {
26+ _dep = super._dep // {
27+ patch = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [
28+ "release.nix"
29+ ".git"
30+ "dist"
31+ "dist-newstyle"
32+ "cabal.haskell-ci"
33+ "cabal.project"
34+ ".travis.yml"
35+ ])) ./.;
36+ };
37+ })
38+ ];
39+ };
40+ in reflex-platform.${ghc}.patch);
3141 in compilerPkgs // {
3242 cache = reflex-platform.pinBuildInputs "patch-${system}"
3343 (builtins.attrValues compilerPkgs);
src/Data/Patch/IntMap.hs+23−10
@@ -1,12 +1,15 @@
1−{-# LANGUAGE DeriveFoldable #-}
2−{-# LANGUAGE DeriveFunctor #-}
31{-# LANGUAGE DeriveTraversable #-}
2+{-# LANGUAGE FlexibleInstances #-}
43{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
5+{-# LANGUAGE TemplateHaskell #-}
56{-# LANGUAGE TypeFamilies #-}
7+
68-- | Module containing 'PatchIntMap', a 'Patch' for 'IntMap' which allows for
79-- insert/update or delete of associations.
810module Data.Patch.IntMap where
911
12+import Control.Lens
1013import Data.IntMap.Strict (IntMap)
1114import qualified Data.IntMap.Strict as IntMap
1215import Data.Maybe
@@ -16,7 +19,20 @@ import Data.Patch.Class
1619-- | 'Patch' for 'IntMap' which represents insertion or deletion of keys in the mapping.
1720-- Internally represented by 'IntMap (Maybe a)', where @Just@ means insert/update
1821-- and @Nothing@ means delete.
19−newtype PatchIntMap a = PatchIntMap (IntMap (Maybe a)) deriving (Functor, Foldable, Traversable, Monoid)
22+newtype PatchIntMap a = PatchIntMap { unPatchIntMap :: IntMap (Maybe a) }
23+ deriving ( Show, Read, Eq, Ord
24+ , Functor, Foldable, Traversable, Monoid
25+ )
26+
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
29+-- precedence.
30+instance 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
34+
35+makeWrapped ''PatchIntMap
2036
2137-- | Apply the insertions or deletions to a given 'IntMap'.
2238instance Patch (PatchIntMap a) where
@@ -26,13 +42,10 @@ instance Patch (PatchIntMap a) where
2642 adds = IntMap.mapMaybe id p
2743 in IntMap.union adds $ v `IntMap.difference` removes
2844
29−-- | @a <> b@ will apply the changes of @b@ and then apply the changes of @a@.
30−-- If the same key is modified by both patches, the one on the left will take
31−-- precedence.
32−instance Semigroup (PatchIntMap v) where
33− PatchIntMap a <> PatchIntMap b = PatchIntMap $ a `mappend` b --TODO: Add a semigroup instance for Map
34− -- PatchMap is idempotent, so stimes n is id for every n
35− stimes = stimesIdempotentMonoid
45+instance FunctorWithIndex Int PatchIntMap
46+instance FoldableWithIndex Int PatchIntMap
47+instance TraversableWithIndex Int PatchIntMap where
48+ itraversed = _Wrapped . itraversed . traversed
3649
3750-- | Map a function @Int -> a -> b@ over all @a@s in the given @'PatchIntMap' a@
3851-- (that is, all inserts/updates), producing a @PatchIntMap b@.
src/Data/Patch/Map.hs+28−13
@@ -1,11 +1,18 @@
1+{-# LANGUAGE DeriveTraversable #-}
2+{-# LANGUAGE FlexibleInstances #-}
13{-# LANGUAGE LambdaCase #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
5+{-# LANGUAGE StandaloneDeriving #-}
6+{-# LANGUAGE TemplateHaskell #-}
27{-# LANGUAGE TypeFamilies #-}
8+
39-- | 'Patch'es on 'Map' that consist only of insertions (including overwrites)
410-- and deletions
511module Data.Patch.Map where
612
713import Data.Patch.Class
814
15+import Control.Lens
916import Data.Map (Map)
1017import qualified Data.Map as Map
1118import Data.Maybe
@@ -15,7 +22,23 @@ import Data.Semigroup
1522-- deleted. Insertions are represented as values wrapped in 'Just', while
1623-- deletions are represented as 'Nothing's
1724newtype PatchMap k v = PatchMap { unPatchMap :: Map k (Maybe v) }
18− deriving (Show, Read, Eq, Ord)
25+ deriving ( Show, Read, Eq, Ord
26+ , Foldable, Traversable
27+ )
28+
29+-- | 'fmap'ping a 'PatchMap' will alter all of the values it will insert.
30+-- Deletions are unaffected.
31+deriving instance Functor (PatchMap k)
32+
33+-- | @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
35+-- precedence.
36+instance Ord k => Semigroup (PatchMap k v) where
37+ PatchMap a <> PatchMap b = PatchMap $ a `mappend` b --TODO: Add a semigroup instance for Map
38+ -- PatchMap is idempotent, so stimes n is id for every n
39+ stimes = stimesIdempotentMonoid
40+
41+makeWrapped ''PatchMap
1942
2043-- | Apply the insertions or deletions to a given 'Map'.
2144instance Ord k => Patch (PatchMap k v) where
@@ -28,24 +51,16 @@ instance Ord k => Patch (PatchMap k v) where
2851 Nothing -> Just ()
2952 Just _ -> Nothing
3053
31−-- | @a <> b@ will apply the changes of @b@ and then apply the changes of @a@.
32−-- If the same key is modified by both patches, the one on the left will take
33−-- precedence.
34−instance Ord k => Semigroup (PatchMap k v) where
35− PatchMap a <> PatchMap b = PatchMap $ a `mappend` b --TODO: Add a semigroup instance for Map
36− -- PatchMap is idempotent, so stimes n is id for every n
37− stimes = stimesIdempotentMonoid
54+instance FunctorWithIndex k (PatchMap k)
55+instance FoldableWithIndex k (PatchMap k)
56+instance TraversableWithIndex k (PatchMap k) where
57+ itraverse f (PatchMap x) = PatchMap <$> itraverse (traverse . f) x
3858
3959-- | The empty 'PatchMap' contains no insertions or deletions
4060instance Ord k => Monoid (PatchMap k v) where
4161 mempty = PatchMap mempty
4262 mappend = (<>)
4363
44−-- | 'fmap'ping a 'PatchMap' will alter all of the values it will insert.
45−-- Deletions are unaffected.
46−instance Functor (PatchMap k) where
47− fmap f = PatchMap . fmap (fmap f) . unPatchMap
48−
4964-- | Returns all the new elements that will be added to the 'Map'
5065patchMapNewElements :: PatchMap k v -> [v]
5166patchMapNewElements (PatchMap p) = catMaybes $ Map.elems p
src/Data/Patch/MapWithMove.hs+20−7
@@ -1,11 +1,14 @@
1−{-# LANGUAGE DeriveFoldable #-}
2−{-# LANGUAGE DeriveFunctor #-}
31{-# LANGUAGE DeriveTraversable #-}
42{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE FlexibleInstances #-}
54{-# LANGUAGE LambdaCase #-}
5+{-# LANGUAGE MultiParamTypeClasses #-}
66{-# LANGUAGE PatternGuards #-}
77{-# LANGUAGE ScopedTypeVariables #-}
8+{-# LANGUAGE TemplateHaskell #-}
9+{-# LANGUAGE TypeApplications #-}
810{-# LANGUAGE TypeFamilies #-}
11+
912-- | 'Patch'es on 'Map' that can insert, delete, and move values from one key to
1013-- another
1114module Data.Patch.MapWithMove where
@@ -13,6 +16,7 @@ module Data.Patch.MapWithMove where
1316import Data.Patch.Class
1417
1518import Control.Arrow
19+import Control.Lens hiding (from, to)
1620import Control.Monad.Trans.State
1721import Data.Foldable
1822import Data.Function
@@ -28,7 +32,13 @@ import Data.Tuple
2832-- | Patch a Map with additions, deletions, and moves. Invariant: If key @k1@
2933-- is coming from @From_Move k2@, then key @k2@ should be going to @Just k1@,
3034-- and vice versa. There should never be any unpaired From/To keys.
31−newtype PatchMapWithMove k v = PatchMapWithMove (Map k (NodeInfo k v)) deriving (Show, Eq, Ord, Functor, Foldable, Traversable)
35+newtype PatchMapWithMove k v = PatchMapWithMove
36+ { -- | Extract the internal representation of the 'PatchMapWithMove'
37+ unPatchMapWithMove :: Map k (NodeInfo k v)
38+ }
39+ deriving ( Show, Read, Eq, Ord
40+ , Functor, Foldable, Traversable
41+ )
3242
3343-- | Holds the information about each key: where its new value should come from,
3444-- and where its old value should go to
@@ -53,6 +63,13 @@ data From k v
5363-- that means it will be deleted.
5464type To = Maybe
5565
66+makeWrapped ''PatchMapWithMove
67+
68+instance FunctorWithIndex k (PatchMapWithMove k)
69+instance FoldableWithIndex k (PatchMapWithMove k)
70+instance TraversableWithIndex k (PatchMapWithMove k) where
71+ itraverse f (PatchMapWithMove x) = PatchMapWithMove <$> itraverse (traverse . f) x
72+
5673-- | Create a 'PatchMapWithMove', validating it
5774patchMapWithMove :: Ord k => Map k (NodeInfo k v) -> Maybe (PatchMapWithMove k v)
5875patchMapWithMove m = if valid then Just $ PatchMapWithMove m else Nothing
@@ -70,10 +87,6 @@ patchMapWithMoveInsertAll m = PatchMapWithMove $ flip fmap m $ \v -> NodeInfo
7087 , _nodeInfo_to = Nothing
7188 }
7289
73−-- | Extract the internal representation of the 'PatchMapWithMove'
74−unPatchMapWithMove :: PatchMapWithMove k v -> Map k (NodeInfo k v)
75−unPatchMapWithMove (PatchMapWithMove p) = p
76−
7790-- | Make a @'PatchMapWithMove' k v@ which has the effect of inserting or updating a value @v@ to the given key @k@, like 'Map.insert'.
7891insertMapKey :: k -> v -> PatchMapWithMove k v
7992insertMapKey k v = PatchMapWithMove . Map.singleton k $ NodeInfo (From_Insert v) Nothing