packages feed

nonempty-containers 0.1.0.0 → 0.1.1.0

raw patch · 10 files changed

+123/−24 lines, 10 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.IntMap.NonEmpty.Internal: instance Control.Comonad.Comonad Data.IntMap.NonEmpty.Internal.NEIntMap
+ Data.Map.NonEmpty.Internal: instance Control.Comonad.Comonad (Data.Map.NonEmpty.Internal.NEMap k)

Files

CHANGELOG.md view
@@ -1,6 +1,18 @@ Changelog ========= +Version 0.1.1.0+---------------++*December 8, 2018*++<https://github.com/mstksg/nonempty-containres/releases/tag/v0.1.1.0>++*   `Comonad` instances added for `Map k` and `IntMap`, based on [Faucelme's+    suggestion][comonad]++[comonad]: https://www.reddit.com/r/haskell/comments/a1qjcy/nonemptycontainers_nonempty_variants_of/eat5r4h/+ Version 0.1.0.0 --------------- 
README.md view
@@ -1,10 +1,12 @@-# nonempty-containers+# [nonempty-containers][] +[nonempty-containers]: http://hackage.haskell.org/package/nonempty-containers+ Efficient and optimized non-empty (by construction) versions of types from *[containers][]*. Inspired by *[non-empty-containers][]* library, except attempting a more faithful port (with under-the-hood optimizations) of the full *containers* API.  Also contains a convenient typeclass abstraction for-converting betwewen non-empty and possibly-empty variants, as well as pattern+converting between non-empty and possibly-empty variants, as well as pattern synonym-based conversion methods.  [containers]: http://hackage.haskell.org/package/containers@@ -43,7 +45,7 @@                    | That    b                    | These a b -    mapEither :: (a -> Either b c) -> NEMap k a -> These (NEMap k c) (NEMap k c)+    mapEither :: (a -> Either b c) -> NEMap k a -> These (NEMap k b) (NEMap k c)     ```      This preserves the invariance of non-emptiness: either we have a non-empty@@ -83,13 +85,19 @@  *   [non-empty-containers][]: Similar approach with similar data types, but API     is limited to a few choice functions.+*   [nonemptymap][]: Another similar approach, but is limited only to `Map`,+    and is also not a complete API port.+*   [non-empty-sequence][]: Similar to *nonemptymap*, but for `Seq`.  Also not+    a complete API port. *   [non-empty][]: Similar approach with similar data types, but is meant to be     more general and work for a variety of more data types. *   [nonempty-alternative][]: Similar approach, but is instead a generalized     data type for all `Alternative` instances. -[non-empty]: http://hackage.haskell.org/package/non-empty-[nonempty-alternative]: http://hackage.haskell.org/package/nonempty-alternative+[nonemptymap]: https://hackage.haskell.org/package/nonemptymap+[non-empty-sequence]: https://hackage.haskell.org/package/non-empty-sequence+[non-empty]: https://hackage.haskell.org/package/non-empty+[nonempty-alternative]: https://hackage.haskell.org/package/nonempty-alternative  Currently not implemented: 
nonempty-containers.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: bc9e6411940584bc108b18b524d5f1ef9a293724bd59219e1b637fc2d2566ea3+-- hash: b3390900b6f311b7cb393b0a328b14e8230f664849c6776e7e225bb4abdaa6e1  name:           nonempty-containers-version:        0.1.0.0+version:        0.1.1.0 synopsis:       Non-empty variants of containers data types, with full API description:    Efficient and optimized non-empty versions of types from /containers/.                 Inspired by /non-empty-containers/ library, except attempting a more
src/Data/IntMap/NonEmpty/Internal.hs view
@@ -56,6 +56,7 @@   ) where  import           Control.Applicative+import           Control.Comonad import           Control.DeepSeq import           Data.Coerce import           Data.Data@@ -73,6 +74,7 @@ import           Text.Read import qualified Data.Foldable              as F import qualified Data.IntMap                as M+import qualified Data.List                  as L import qualified Data.Semigroup.Foldable    as F1  -- | A non-empty (by construction) map from integer keys to values @a@.  At@@ -548,8 +550,7 @@ -- elements in order of ascending keys, while 'IntMap' traverses positive -- keys first, then negative keys. instance Foldable1 NEIntMap where-    fold1 (NEIntMap _ v m) = maybe v (v <>)-                           . getOption+    fold1 (NEIntMap _ v m) = option v (v <>)                            . F.foldMap (Option . Just)                            . M.elems                            $ m@@ -568,6 +569,28 @@ instance Traversable1 NEIntMap where     traverse1 f = traverseWithKey1 (const f)     {-# INLINE traverse1 #-}++-- | 'extract' gets the value at the minimal key, and 'duplicate' produces+-- a map of maps comprised of all keys from the original map greater than+-- or equal to the current key.+--+-- @since 0.1.1.0+instance Comonad NEIntMap where+    extract = neimV0+    {-# INLINE extract #-}+    -- We'd like to use 'M.mapAccumWithKey', but it traverses things in the+    -- wrong order.+    duplicate n0@(NEIntMap k0 _ m0) = NEIntMap k0 n0+                                    . M.fromDistinctAscList+                                    . snd+                                    . L.mapAccumL go m0+                                    . M.toList+                                    $ m0+      where+        go m (k, v) = (m', (k, NEIntMap k v m'))+          where+            !m' = M.deleteMin m+    {-# INLINE duplicate #-}  -- | /O(n)/. Test if the internal map structure is valid. valid :: NEIntMap a -> Bool
src/Data/Map/NonEmpty/Internal.hs view
@@ -51,6 +51,7 @@   ) where  import           Control.Applicative+import           Control.Comonad import           Control.DeepSeq import           Data.Coerce import           Data.Data@@ -263,8 +264,7 @@     => (k -> a -> m)     -> NEMap k a     -> m-foldMapWithKey f (NEMap k0 v m) = maybe (f k0 v) (f k0 v <>)-                                . getOption+foldMapWithKey f (NEMap k0 v m) = option (f k0 v) (f k0 v <>)                                 . M.foldMapWithKey (\k -> Option . Just . f k)                                 $ m {-# INLINE foldMapWithKey #-}@@ -534,8 +534,7 @@  -- | Traverses elements in order of ascending keys instance Foldable1 (NEMap k) where-    fold1 (NEMap _ v m) = maybe v (v <>)-                        . getOption+    fold1 (NEMap _ v m) = option v (v <>)                         . F.foldMap (Option . Just)                         $ m     {-# INLINE fold1 #-}@@ -554,6 +553,23 @@       where         m1 = traverse (MaybeApply . Left) m0     {-# INLINABLE sequence1 #-}++-- | 'extract' gets the value at the minimal key, and 'duplicate' produces+-- a map of maps comprised of all keys from the original map greater than+-- or equal to the current key.+--+-- @since 0.1.1.0+instance Comonad (NEMap k) where+    extract = nemV0+    {-# INLINE extract #-}+    duplicate n0@(NEMap k0 _ m0) = NEMap k0 n0 . snd+                                 . M.mapAccumWithKey go m0+                                 $ m0+      where+        go m k v = (m', NEMap k v m')+          where+            !m' = M.deleteMin m+    {-# INLINE duplicate #-}  -- | /O(n)/. Test if the internal map structure is valid. valid :: Ord k => NEMap k a -> Bool
src/Data/Sequence/NonEmpty/Internal.hs view
@@ -301,8 +301,7 @@ -- a folding function that also depends on the element's index, and applies -- it to every element in the sequence. foldMapWithIndex :: Semigroup m => (Int -> a -> m) -> NESeq a -> m-foldMapWithIndex f (x :<|| xs) = maybe (f 0 x) (f 0 x <>)-                               . getOption+foldMapWithIndex f (x :<|| xs) = option (f 0 x) (f 0 x <>)                                . Seq.foldMapWithIndex (\i -> Option . Just . f (i + 1))                                $ xs {-# INLINE foldMapWithIndex #-}@@ -416,7 +415,7 @@     extend = extended     {-# INLINE extend #-} --- | 'foldr1', 'foldl', 'maximum', and 'minimum' are all total, unlike for+-- | 'foldr1', 'foldl1', 'maximum', and 'minimum' are all total, unlike for -- 'Seq'. instance Foldable NESeq where #if MIN_VERSION_base(4,11,0)@@ -452,8 +451,7 @@     {-# INLINE length #-}  instance Foldable1 NESeq where-    fold1 (x :<|| xs) = maybe x (x <>)-                      . getOption+    fold1 (x :<|| xs) = option x (x <>)                       . F.foldMap (Option . Just)                       $ xs     {-# INLINE fold1 #-}
src/Data/Set/NonEmpty/Internal.hs view
@@ -368,14 +368,12 @@  -- | Traverses elements in ascending order instance Foldable1 NESet where-    fold1 (NESet x s) = maybe x (x <>)-                      . getOption+    fold1 (NESet x s) = option x (x <>)                       . F.foldMap (Option . Just)                       $ s     {-# INLINE fold1 #-}     -- TODO: benchmark against maxView-based method-    foldMap1 f (NESet x s) = maybe (f x) (f x <>)-                           . getOption+    foldMap1 f (NESet x s) = option (f x) (f x <>)                            . F.foldMap (Option . Just . f)                            $ s     {-# INLINE foldMap1 #-}
test/Spec.hs view
@@ -1,7 +1,7 @@ +-- import           Test.Tasty.Hedgehog+-- import           Test.Tasty.Ingredients.ConsoleReporter import           Test.Tasty-import           Test.Tasty.Hedgehog-import           Test.Tasty.Ingredients.ConsoleReporter import           Tests.IntMap import           Tests.IntSet import           Tests.Map
test/Tests/IntMap.hs view
@@ -5,6 +5,7 @@ module Tests.IntMap (intMapTests) where  import           Control.Applicative+import           Control.Comonad import           Data.Coerce import           Data.Foldable import           Data.Functor.Identity@@ -109,6 +110,26 @@       Nothing          -> True       Just ys@(y :| _) -> x < y && ascending ys +prop_extract_duplicate :: Property+prop_extract_duplicate = property $ do+    n <- forAll neIntMapGen+    tripping n duplicate+               (Identity . extract)++prop_fmap_extract_duplicate :: Property+prop_fmap_extract_duplicate = property $ do+    n <- forAll neIntMapGen+    tripping n duplicate+               (Identity . fmap extract)++prop_duplicate_duplicate :: Property+prop_duplicate_duplicate = property $ do+    n <- forAll neIntMapGen+    let dd1 = duplicate . duplicate      $ n+        dd2 = fmap duplicate . duplicate $ n+    assert $ NEM.valid dd1+    assert $ NEM.valid dd2+    dd1 === dd2   
test/Tests/Map.hs view
@@ -4,6 +4,7 @@ module Tests.Map (mapTests) where  import           Control.Applicative+import           Control.Comonad import           Data.Coerce import           Data.Foldable import           Data.Functor.Identity@@ -110,6 +111,28 @@     ascending (x :| xs) = case NE.nonEmpty xs of       Nothing          -> True       Just ys@(y :| _) -> x < y && ascending ys++prop_extract_duplicate :: Property+prop_extract_duplicate = property $ do+    n <- forAll neMapGen+    tripping n duplicate+               (Identity . extract)++prop_fmap_extract_duplicate :: Property+prop_fmap_extract_duplicate = property $ do+    n <- forAll neMapGen+    tripping n duplicate+               (Identity . fmap extract)++prop_duplicate_duplicate :: Property+prop_duplicate_duplicate = property $ do+    n <- forAll neMapGen+    let dd1 = duplicate . duplicate      $ n+        dd2 = fmap duplicate . duplicate $ n+    assert $ NEM.valid dd1+    assert $ NEM.valid dd2+    dd1 === dd2+