packages feed

extra 1.7.16 → 1.8

raw patch · 9 files changed

+113/−18 lines, 9 filesdep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base

API changes (from Hackage documentation)

+ Control.Monad.Extra: guarded :: Alternative m => (a -> Bool) -> a -> m a
+ Control.Monad.Extra: guardedA :: (Functor f, Alternative m) => (a -> f Bool) -> a -> f (m a)
+ Data.Foldable.Extra: compareLength :: Foldable f => f a -> Int -> Ordering
+ Data.List.NonEmpty.Extra: compareLength :: NonEmpty a -> Int -> Ordering
+ Extra: guarded :: Alternative m => (a -> Bool) -> a -> m a
+ Extra: guardedA :: (Functor f, Alternative m) => (a -> f Bool) -> a -> f (m a)
- Data.List.Extra: compareLength :: (Ord b, Num b, Foldable f) => f a -> b -> Ordering
+ Data.List.Extra: compareLength :: [a] -> Int -> Ordering
- Extra: compareLength :: (Ord b, Num b, Foldable f) => f a -> b -> Ordering
+ Extra: compareLength :: [a] -> Int -> Ordering

Files

CHANGES.txt view
@@ -1,5 +1,9 @@-Changelog for Extra+Changelog for Extra (* = breaking change) +1.8, released 2024-10-19+    #109, add guarded to lift predicates into Alternatives+*   #112, make Data.List.Extra.compareLength work on list/int only+    #112, add compareLength to List.NonEmpty and Foldable 1.7.16, released 2024-05-11     Fix to actually work with GHC 9.10 1.7.15, released 2024-05-10
Generate.hs view
@@ -86,7 +86,7 @@  hidden :: String -> [String] hidden "Data.List.NonEmpty.Extra" = words-    "cons snoc sortOn union unionBy nubOrd nubOrdBy nubOrdOn (!?) foldl1' repeatedly"+    "cons snoc sortOn union unionBy nubOrd nubOrdBy nubOrdOn (!?) foldl1' repeatedly compareLength" hidden _ = []  notHidden :: String -> String -> Bool
extra.cabal view
@@ -1,7 +1,7 @@ cabal-version:      1.18 build-type:         Simple name:               extra-version:            1.7.16+version:            1.8 license:            BSD3 license-file:       LICENSE category:           Development@@ -15,7 +15,7 @@     The module "Extra" documents all functions provided by this library. Modules such as "Data.List.Extra" provide extra functions over "Data.List" and also reexport "Data.List". Users are recommended to replace "Data.List" imports with "Data.List.Extra" if they need the extra functionality. homepage:           https://github.com/ndmitchell/extra#readme bug-reports:        https://github.com/ndmitchell/extra/issues-tested-with:        GHC==9.8, GHC==9.6, GHC==9.4, GHC==9.2, GHC==9.0, GHC==8.10, GHC==8.8+tested-with:        GHC==9.10, GHC==9.8, GHC==9.6, GHC==9.4, GHC==9.2, GHC==9.0, GHC==8.10, GHC==8.8  extra-doc-files:     CHANGES.txt
src/Control/Monad/Extra.hs view
@@ -11,6 +11,7 @@     whenMaybe, whenMaybeM,     unit,     maybeM, fromMaybeM, eitherM,+    guarded, guardedA,     -- * Loops     loop, loopM, whileM, whileJustM, untilJustM,     -- * Lists@@ -87,6 +88,24 @@ -- | Monadic generalisation of 'either'. eitherM :: Monad m => (a -> m c) -> (b -> m c) -> m (Either a b) -> m c eitherM l r x = either l r =<< x++-- | Either lifts a value into an alternative context or gives a+--   minimal value depending on a predicate. Works with 'Alternative's.+--+-- > guarded even 2 == [2]+-- > guarded odd 2 == Nothing+-- > guarded (not.null) "My Name" == Just "My Name"+guarded :: Alternative m => (a -> Bool) -> a -> m a+guarded pred x = if pred x then pure x else empty++-- | A variant of `guarded` using 'Functor'-wrapped values.+--+-- > guardedA (return . even) 42    == Just [42]+-- > guardedA (return . odd) 42     == Just []+-- > guardedA (const Nothing) 42    == (Nothing :: Maybe [Int])+guardedA :: (Functor f, Alternative m) => (a -> f Bool) -> a -> f (m a)+guardedA pred x = fmap inner (pred x)+    where inner b = if b then pure x else empty  -- | A variant of 'foldM' that has no base case, and thus may only be applied to non-empty lists. --
src/Data/Foldable/Extra.hs view
@@ -11,6 +11,7 @@     , andM     , findM     , firstJustM+    , compareLength     ) where  import Data.Foldable@@ -59,3 +60,12 @@ -- | A generalization of 'Control.Monad.Extra.firstJustM' to 'Foldable' instances. firstJustM :: (Foldable f, Monad m) => (a -> m (Maybe b)) -> f a -> m (Maybe b) firstJustM p = MX.firstJustM p . toList++-- | Lazily compare the length of a 'Foldable' with a number.+--+-- > compareLength [1,2,3] 1 == GT+-- > compareLength [1,2] 2 == EQ+-- > \(xs :: [Int]) n -> compareLength xs n == compare (length xs) n+-- > compareLength (1:2:3:undefined) 2 == GT+compareLength :: Foldable f => f a -> Int -> Ordering+compareLength = foldr (\_ acc n -> if n > 0 then acc (n - 1) else GT) (compare 0)
src/Data/List/Extra.hs view
@@ -902,14 +902,41 @@ zipWithLongest f [] ys = map (f Nothing . Just) ys zipWithLongest f xs [] = map ((`f` Nothing) . Just) xs --- | Lazily compare the length of a 'Foldable' with a number.+#if __GLASGOW_HASKELL__ <= 910+-- | Use 'compareLength' @xs@ @n@ as a safer and faster alternative+-- to 'compare' ('length' @xs@) @n@. Similarly, it's better+-- to write @compareLength xs 10 == LT@ instead of @length xs < 10@. ----- > compareLength [1,2,3] 1 == GT--- > compareLength [1,2] 2 == EQ--- > \(xs :: [Int]) n -> compareLength xs n == compare (length xs) n--- > compareLength (1:2:3:undefined) 2 == GT-compareLength :: (Ord b, Num b, Foldable f) => f a -> b -> Ordering-compareLength = foldr (\_ acc n -> if n > 0 then acc (n - 1) else GT) (compare 0)+-- While 'length' would force and traverse+-- the entire spine of @xs@ (which could even diverge if @xs@ is infinite),+-- 'compareLength' traverses at most @n@ elements to determine its result.+--+-- >>> compareLength [] 0+-- EQ+-- >>> compareLength [] 1+-- LT+-- >>> compareLength ['a'] 1+-- EQ+-- >>> compareLength ['a', 'b'] 1+-- GT+-- >>> compareLength [0..] 100+-- GT+-- >>> compareLength undefined (-1)+-- GT+-- >>> compareLength ('a' : undefined) 0+-- GT+--+-- @since 4.21.0.0+--+compareLength :: [a] -> Int -> Ordering+compareLength xs n+  | n < 0 = GT+  | otherwise = foldr+    (\_ f m -> if m > 0 then f (m - 1) else GT)+    (\m -> if m > 0 then LT else EQ)+    xs+    n+#endif  -- | Lazily compare the length of two 'Foldable's. -- > comparingLength [1,2,3] [False] == GT
src/Data/List/NonEmpty/Extra.hs view
@@ -10,7 +10,8 @@     sortOn, union, unionBy,     nubOrd, nubOrdBy, nubOrdOn,     maximum1, minimum1, maximumBy1, minimumBy1, maximumOn1, minimumOn1,-    foldl1', repeatedly+    foldl1', repeatedly,+    compareLength     ) where  import           Data.Function@@ -137,3 +138,35 @@ repeatedly :: (NonEmpty a -> (b, [a])) -> NonEmpty a -> NonEmpty b repeatedly f (a :| as) = b :| List.repeatedlyNE f as'     where (b, as') = f (a :| as)++#if __GLASGOW_HASKELL__ <= 910+-- | Use 'compareLength' @xs@ @n@ as a safer and faster alternative+-- to 'compare' ('length' @xs@) @n@. Similarly, it's better+-- to write @compareLength xs 10 == LT@ instead of @length xs < 10@.+--+-- While 'length' would force and traverse+-- the entire spine of @xs@ (which could even diverge if @xs@ is infinite),+-- 'compareLength' traverses at most @n@ elements to determine its result.+--+-- >>> compareLength ('a' :| []) 1+-- EQ+-- >>> compareLength ('a' :| ['b']) 3+-- LT+-- >>> compareLength (0 :| [1..]) 100+-- GT+-- >>> compareLength undefined 0+-- GT+-- >>> compareLength ('a' :| 'b' : undefined) 1+-- GT+--+-- @since 4.21.0.0+--+compareLength :: NonEmpty a -> Int -> Ordering+compareLength xs n+  | n < 1 = GT+  | otherwise = foldr+    (\_ f m -> if m > 0 then f (m - 1) else GT)+    (\m -> if m > 0 then LT else EQ)+    xs+    n+#endif
src/Extra.hs view
@@ -14,7 +14,7 @@     Partial, retry, retryBool, errorWithoutStackTrace, showException, stringException, errorIO, assertIO, ignore, catch_, handle_, try_, catchJust_, handleJust_, tryJust_, catchBool, handleBool, tryBool,     -- * Control.Monad.Extra     -- | Extra functions available in @"Control.Monad.Extra"@.-    whenJust, whenJustM, pureIf, whenMaybe, whenMaybeM, unit, maybeM, fromMaybeM, eitherM, loop, loopM, whileM, whileJustM, untilJustM, partitionM, concatMapM, concatForM, mconcatMapM, mapMaybeM, findM, firstJustM, fold1M, fold1M_, whenM, unlessM, ifM, notM, (||^), (&&^), orM, andM, anyM, allM,+    whenJust, whenJustM, pureIf, whenMaybe, whenMaybeM, unit, maybeM, fromMaybeM, eitherM, guarded, guardedA, loop, loopM, whileM, whileJustM, untilJustM, partitionM, concatMapM, concatForM, mconcatMapM, mapMaybeM, findM, firstJustM, fold1M, fold1M_, whenM, unlessM, ifM, notM, (||^), (&&^), orM, andM, anyM, allM,     -- * Data.Either.Extra     -- | Extra functions available in @"Data.Either.Extra"@.     fromLeft, fromRight, fromEither, fromLeft', fromRight', eitherToMaybe, maybeToEither, mapLeft, mapRight,@@ -62,7 +62,7 @@ import Data.Either.Extra import Data.IORef.Extra import Data.List.Extra-import Data.List.NonEmpty.Extra hiding (cons, snoc, sortOn, union, unionBy, nubOrd, nubOrdBy, nubOrdOn, (!?), foldl1', repeatedly)+import Data.List.NonEmpty.Extra hiding (cons, snoc, sortOn, union, unionBy, nubOrd, nubOrdBy, nubOrdOn, (!?), foldl1', repeatedly, compareLength) import Data.Monoid.Extra import Data.Tuple.Extra import Data.Version.Extra
test/TestGen.hs view
@@ -38,6 +38,12 @@     testGen "whenMaybe True  (print 1) == fmap Just (print 1)" $ whenMaybe True  (print 1) == fmap Just (print 1)     testGen "whenMaybe False (print 1) == pure Nothing" $ whenMaybe False (print 1) == pure Nothing     testGen "\\(x :: Maybe ()) -> unit x == x" $ \(x :: Maybe ()) -> unit x == x+    testGen "guarded even 2 == [2]" $ guarded even 2 == [2]+    testGen "guarded odd 2 == Nothing" $ guarded odd 2 == Nothing+    testGen "guarded (not.null) \"My Name\" == Just \"My Name\"" $ guarded (not.null) "My Name" == Just "My Name"+    testGen "guardedA (return . even) 42    == Just [42]" $ guardedA (return . even) 42    == Just [42]+    testGen "guardedA (return . odd) 42     == Just []" $ guardedA (return . odd) 42     == Just []+    testGen "guardedA (const Nothing) 42    == (Nothing :: Maybe [Int])" $ guardedA (const Nothing) 42    == (Nothing :: Maybe [Int])     testGen "fold1M (\\x y -> Just x) [] == undefined" $ erroneous $ fold1M (\x y -> Just x) []     testGen "fold1M (\\x y -> Just $ x + y) [1, 2, 3] == Just 6" $ fold1M (\x y -> Just $ x + y) [1, 2, 3] == Just 6     testGen "partitionM (Just . even) [1,2,3] == Just ([2], [1,3])" $ partitionM (Just . even) [1,2,3] == Just ([2], [1,3])@@ -264,10 +270,6 @@     testGen "zipWithLongest (,) \"a\" \"xyz\" == [(Just 'a', Just 'x'), (Nothing, Just 'y'), (Nothing, Just 'z')]" $ zipWithLongest (,) "a" "xyz" == [(Just 'a', Just 'x'), (Nothing, Just 'y'), (Nothing, Just 'z')]     testGen "zipWithLongest (,) \"a\" \"x\" == [(Just 'a', Just 'x')]" $ zipWithLongest (,) "a" "x" == [(Just 'a', Just 'x')]     testGen "zipWithLongest (,) \"\" \"x\" == [(Nothing, Just 'x')]" $ zipWithLongest (,) "" "x" == [(Nothing, Just 'x')]-    testGen "compareLength [1,2,3] 1 == GT" $ compareLength [1,2,3] 1 == GT-    testGen "compareLength [1,2] 2 == EQ" $ compareLength [1,2] 2 == EQ-    testGen "\\(xs :: [Int]) n -> compareLength xs n == compare (length xs) n" $ \(xs :: [Int]) n -> compareLength xs n == compare (length xs) n-    testGen "compareLength (1:2:3:undefined) 2 == GT" $ compareLength (1:2:3:undefined) 2 == GT     testGen "comparingLength [1,2,3] [False] == GT" $ comparingLength [1,2,3] [False] == GT     testGen "comparingLength [1,2] \"ab\" == EQ" $ comparingLength [1,2] "ab" == EQ     testGen "\\(xs :: [Int]) (ys :: [Int]) -> comparingLength xs ys == Data.Ord.comparing length xs ys" $ \(xs :: [Int]) (ys :: [Int]) -> comparingLength xs ys == Data.Ord.comparing length xs ys