packages feed

extra 1.7.9 → 1.7.10

raw patch · 11 files changed

+95/−34 lines, 11 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Control.Concurrent.Extra: modifyVar' :: Var a -> (a -> IO (a, b)) -> IO b
+ Control.Concurrent.Extra: modifyVar_' :: Var a -> (a -> IO a) -> IO ()
+ Control.Concurrent.Extra: writeVar' :: Var a -> a -> IO ()
+ Control.Exception.Extra: assertIO :: Partial => Bool -> IO ()
+ Data.List.Extra: (!?) :: [a] -> Int -> Maybe a
+ Data.List.NonEmpty.Extra: (!?) :: NonEmpty a -> Int -> Maybe a
+ Data.List.NonEmpty.Extra: infixl 9 !?
+ Extra: (!?) :: [a] -> Int -> Maybe a
+ Extra: assertIO :: Partial => Bool -> IO ()
+ Extra: modifyVar' :: Var a -> (a -> IO (a, b)) -> IO b
+ Extra: modifyVar_' :: Var a -> (a -> IO a) -> IO ()
+ Extra: writeVar' :: Var a -> a -> IO ()

Files

CHANGES.txt view
@@ -1,5 +1,9 @@ Changelog for Extra +1.7.10, released 2021-08-29+    #81, add assertIO function+    #85, add !? to do !! list indexing returning a Maybe+    #80, add strict Var functions modifyVar', modifyVar_', writeVar' 1.7.9, released 2020-12-19     #72, add pureIf     #73, make takeEnd, dropEnd, splitAtEnd: return immediately if i <= 0
Generate.hs view
@@ -1,5 +1,5 @@ -- This module generates the files src/Extra.hs and test/TestGen.hs.--- Either call "runhaskell Generate" or start "ghci" and use ":generate".+-- Either call "runghc Generate" or start "ghci" and use ":generate".  module Generate(main) where @@ -24,7 +24,7 @@         let funcs = filter validIdentifier $ takeWhile (/= "where") $                     words $ replace "," " " $ drop1 $ dropWhile (/= '(') $                     unlines $ filter (\x -> not $ any (`isPrefixOf` trim x) ["--","#"]) $ lines src-        let tests = mapMaybe (stripPrefix "-- > ") $ lines src+        let tests = if mod `elem` excludeTests then [] else mapMaybe (stripPrefix "-- > ") $ lines src         pure (mod, funcs, tests)     writeFileBinaryChanged "src/Extra.hs" $ unlines $         ["-- GENERATED CODE - DO NOT MODIFY"@@ -49,8 +49,6 @@         ,"{-# LANGUAGE ExtendedDefaultRules, ScopedTypeVariables, TypeApplications, ViewPatterns #-}"         ,"module TestGen(tests) where"         ,"import TestUtil"-        ,"import qualified Data.List"-        ,"import qualified Data.List.NonEmpty.Extra"         ,"import qualified Data.Ord"         ,"import Test.QuickCheck.Instances.Semigroup ()"         ,"default(Maybe Bool,Int,Double,Maybe (Maybe Bool),Maybe (Maybe Char))"@@ -71,11 +69,19 @@         writeFileBinary file x  exclude :: [String]-exclude = ["Data.Foldable.Extra"] -- because all their imports clash+exclude =+    ["Data.Foldable.Extra" -- because all their imports clash+    ] +excludeTests :: [String]+-- FIXME: Should probably generate these in another module+excludeTests =+    ["Data.List.NonEmpty.Extra" -- because !? clashes and is tested+    ]+ hidden :: String -> [String] hidden "Data.List.NonEmpty.Extra" = words-    "cons snoc sortOn union unionBy nubOrd nubOrdBy nubOrdOn"+    "cons snoc sortOn union unionBy nubOrd nubOrdBy nubOrdOn (!?)" hidden _ = []  notHidden :: String -> String -> Bool
LICENSE view
@@ -1,4 +1,4 @@-Copyright Neil Mitchell 2014-2020.+Copyright Neil Mitchell 2014-2021. All rights reserved.  Redistribution and use in source and binary forms, with or without
README.md view
@@ -1,4 +1,4 @@-# Extra [![Hackage version](https://img.shields.io/hackage/v/extra.svg?label=Hackage)](https://hackage.haskell.org/package/extra) [![Stackage version](https://www.stackage.org/package/extra/badge/nightly?label=Stackage)](https://www.stackage.org/package/extra) [![Build status](https://img.shields.io/github/workflow/status/ndmitchell/extra/ci.svg)](https://github.com/ndmitchell/extra/actions)+# Extra [![Hackage version](https://img.shields.io/hackage/v/extra.svg?label=Hackage)](https://hackage.haskell.org/package/extra) [![Stackage version](https://www.stackage.org/package/extra/badge/nightly?label=Stackage)](https://www.stackage.org/package/extra) [![Build status](https://img.shields.io/github/workflow/status/ndmitchell/extra/ci/master.svg)](https://github.com/ndmitchell/extra/actions)  A library of extra functions for the standard Haskell libraries. Most functions are simple additions, filling out missing functionality. A few functions are available in later versions of GHC, but this package makes them available back to GHC 7.10. A few examples: @@ -24,4 +24,4 @@  ## Contributing -My general contribution preferences are [available here](https://github.com/ndmitchell/neil#contributions). In addition, this repo contains some generated code which is checked in, namely [src/Extra.hs](src/Extra.hs) and [test/TestGen.hs](test/TestGen.hs). You can generate those files by either running `runhaskell Generate.hs` or `ghci` (which uses the [`.ghci` file](.ghci)) and typing `:generate`. All PR's should contain regenerated versions of those files.+My general contribution preferences are [available here](https://github.com/ndmitchell/neil#contributions). In addition, this repo contains some generated code which is checked in, namely [src/Extra.hs](src/Extra.hs) and [test/TestGen.hs](test/TestGen.hs). You can generate those files by either running `runghc Generate.hs` or `ghci` (which uses the [`.ghci` file](.ghci)) and typing `:generate`. All PR's should contain regenerated versions of those files.
extra.cabal view
@@ -1,13 +1,13 @@-cabal-version:      >= 1.18+cabal-version:      1.18 build-type:         Simple name:               extra-version:            1.7.9+version:            1.7.10 license:            BSD3 license-file:       LICENSE category:           Development author:             Neil Mitchell <ndmitchell@gmail.com> maintainer:         Neil Mitchell <ndmitchell@gmail.com>-copyright:          Neil Mitchell 2014-2020+copyright:          Neil Mitchell 2014-2021 synopsis:           Extra functions I use. description:     A library of extra functions for the standard Haskell libraries. Most functions are simple additions, filling out missing functionality. A few functions are available in later versions of GHC, but this package makes them available back to GHC 7.2.@@ -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==8.10, GHC==8.8, GHC==8.6, GHC==8.4, GHC==8.2, GHC==8.0+tested-with:        GHC==9.0, GHC==8.10, GHC==8.8, GHC==8.6, GHC==8.4, GHC==8.2, GHC==8.0  extra-doc-files:     CHANGES.txt
src/Control/Concurrent/Extra.hs view
@@ -18,7 +18,11 @@     -- * Lock     Lock, newLock, withLock, withLockTry,     -- * Var-    Var, newVar, readVar, writeVar, modifyVar, modifyVar_, withVar,+    Var, newVar, readVar,+    writeVar, writeVar',+    modifyVar, modifyVar',+    modifyVar_, modifyVar_',+    withVar,     -- * Barrier     Barrier, newBarrier, signalBarrier, waitBarrier, waitBarrierMaybe,     ) where@@ -30,6 +34,7 @@ import Data.Either.Extra import Data.Functor import Prelude+import Data.Tuple.Extra (dupe)   -- | On GHC 7.6 and above with the @-threaded@ flag, brackets a call to 'setNumCapabilities'.@@ -152,13 +157,33 @@ writeVar :: Var a -> a -> IO () writeVar v x = modifyVar_ v $ const $ pure x +-- | Strict variant of 'writeVar'+writeVar' :: Var a -> a -> IO ()+writeVar' v x = modifyVar_' v $ const $ pure x+ -- | Modify a 'Var' producing a new value and a return result. modifyVar :: Var a -> (a -> IO (a, b)) -> IO b modifyVar (Var x) f = modifyMVar x f +-- | Strict variant of 'modifyVar''+modifyVar' :: Var a -> (a -> IO (a, b)) -> IO b+modifyVar' x f = do+    (newContents, res) <- modifyVar x $ \v -> do+        (newContents, res) <- f v+        pure (newContents, (newContents, res))+    evaluate newContents+    pure res+ -- | Modify a 'Var', a restricted version of 'modifyVar'. modifyVar_ :: Var a -> (a -> IO a) -> IO () modifyVar_ (Var x) f = modifyMVar_ x f++-- | Strict variant of 'modifyVar_'+modifyVar_' :: Var a -> (a -> IO a) -> IO ()+modifyVar_' x f = do+    newContents <- modifyVar x (fmap dupe . f)+    _ <- evaluate newContents+    pure ()  -- | Perform some operation using the value in the 'Var', --   a restricted version of 'modifyVar'.
src/Control/Exception/Extra.hs view
@@ -13,7 +13,7 @@     retry, retryBool,     errorWithoutStackTrace,     showException, stringException,-    errorIO,+    errorIO, assertIO,     -- * Exception catching/ignoring     ignore,     catch_, handle_, try_,@@ -85,6 +85,13 @@ withFrozenCallStack = id #endif +-- | An 'IO' action that when evaluated calls 'assert' in the 'IO' monad, which throws an 'AssertionFailed' exception if the argument is 'False'.+--   With optimizations enabled (and @-fgnore-asserts@) this function ignores its argument and does nothing.+--+-- > catch (assertIO True  >> pure 1) (\(x :: AssertionFailed) -> pure 2) == pure 1+-- > seq (assertIO False) (print 1) == print 1+assertIO :: Partial => Bool -> IO ()+assertIO x = withFrozenCallStack $ evaluate $ assert x ()  -- | Retry an operation at most /n/ times (/n/ must be positive). --   If the operation fails the /n/th time it will throw that final exception.
src/Data/List/Extra.hs view
@@ -18,7 +18,7 @@     wordsBy, linesBy,     breakOn, breakOnEnd, splitOn, split, chunksOf,     -- * Basics-    headDef, lastDef, notNull, list, unsnoc, cons, snoc,+    headDef, lastDef, (!?), notNull, list, unsnoc, cons, snoc,     drop1, dropEnd1, mconcatMap, compareLength, comparingLength,     -- * Enum operations     enumerate,@@ -141,6 +141,19 @@ lastDef d xs = foldl (\_ x -> x) d xs -- I know this looks weird, but apparently this is the fastest way to do this: https://hackage.haskell.org/package/base-4.12.0.0/docs/src/GHC.List.html#last {-# INLINE lastDef #-} +-- | A total variant of the list index function `(!!)`.+--+-- > [2,3,4] !? 1    == Just 3+-- > [2,3,4] !? (-1) == Nothing+-- > []      !? 0    == Nothing+(!?) :: [a] -> Int -> Maybe a+xs !? n+  | n < 0     = Nothing+             -- Definition adapted from GHC.List+  | otherwise = foldr (\x r k -> case k of+                                   0 -> Just x+                                   _ -> r (k-1)) (const Nothing) xs n+{-# INLINABLE (!?) #-}  -- | A composition of 'not' and 'null'. --@@ -237,7 +250,7 @@   -- | 'zip' against an enumeration.---   Never truncates the output - raises an error if the enumeration runs out.+--   Truncates the output if the enumeration runs out. -- -- > \i xs -> zip [i..] xs == zipFrom i xs -- > zipFrom False [1..3] == [(False,1),(True, 2)]@@ -245,7 +258,7 @@ zipFrom = zipWithFrom (,)  -- | 'zipFrom' generalised to any combining operation.---   Never truncates the output - raises an error if the enumeration runs out.+--   Truncates the output if the enumeration runs out. -- -- > \i xs -> zipWithFrom (,) i xs == zipFrom i xs zipWithFrom :: Enum a => (a -> b -> c) -> a -> [b] -> [c]
src/Data/List/NonEmpty/Extra.hs view
@@ -4,7 +4,7 @@ --   also exports the existing "Data.List.NonEmpty" functions. module Data.List.NonEmpty.Extra(     module Data.List.NonEmpty,-    (|:), (|>), snoc,+    (|:), (|>), snoc, (!?),     appendl, appendr,     sortOn, union, unionBy,     nubOrd, nubOrdBy, nubOrdOn,@@ -36,6 +36,18 @@ -- > [1,2,3] |: 4 |> 5 == 1 :| [2,3,4,5] (|:) :: [a] -> a -> NonEmpty a (|:) xs x = foldr cons (pure x) xs++-- | A total variant of the list index function `(!?)`.+--+-- > (2 :| [3,4]) !? 1    == Just 3+-- > (2 :| [3,4]) !? (-1) == Nothing+-- > (1 :| [])    !? 1    == Nothing+(!?) :: NonEmpty a -> Int -> Maybe a+(!?) ~(x :| xs) n+  | n == 0 = Just x+  | n > 0  = xs List.!? (n - 1)+  | otherwise = Nothing+infixl 9 !?  -- | Append a list to a non-empty list. --
src/Extra.hs view
@@ -8,10 +8,10 @@ module Extra {-# DEPRECATED "This module is provided as documentation of all new functions, you should import the more specific modules directly." #-} (     -- * Control.Concurrent.Extra     -- | Extra functions available in @"Control.Concurrent.Extra"@.-    withNumCapabilities, once, onceFork, Lock, newLock, withLock, withLockTry, Var, newVar, readVar, writeVar, modifyVar, modifyVar_, withVar, Barrier, newBarrier, signalBarrier, waitBarrier, waitBarrierMaybe,+    withNumCapabilities, once, onceFork, Lock, newLock, withLock, withLockTry, Var, newVar, readVar, writeVar, writeVar', modifyVar, modifyVar', modifyVar_, modifyVar_', withVar, Barrier, newBarrier, signalBarrier, waitBarrier, waitBarrierMaybe,     -- * Control.Exception.Extra     -- | Extra functions available in @"Control.Exception.Extra"@.-    Partial, retry, retryBool, errorWithoutStackTrace, showException, stringException, errorIO, ignore, catch_, handle_, try_, catchJust_, handleJust_, tryJust_, catchBool, handleBool, tryBool,+    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,@@ -23,7 +23,7 @@     writeIORef', atomicWriteIORef', atomicModifyIORef_, atomicModifyIORef'_,     -- * Data.List.Extra     -- | Extra functions available in @"Data.List.Extra"@.-    lower, upper, trim, trimStart, trimEnd, word1, line1, escapeHTML, escapeJSON, unescapeHTML, unescapeJSON, dropEnd, takeEnd, splitAtEnd, breakEnd, spanEnd, dropWhileEnd', takeWhileEnd, stripSuffix, stripInfix, stripInfixEnd, dropPrefix, dropSuffix, wordsBy, linesBy, breakOn, breakOnEnd, splitOn, split, chunksOf, headDef, lastDef, notNull, list, unsnoc, cons, snoc, drop1, dropEnd1, mconcatMap, compareLength, comparingLength, enumerate, groupSort, groupSortOn, groupSortBy, nubOrd, nubOrdBy, nubOrdOn, nubOn, groupOn, nubSort, nubSortBy, nubSortOn, maximumOn, minimumOn, sum', product', sumOn', productOn', disjoint, disjointOrd, disjointOrdBy, allSame, anySame, repeatedly, firstJust, concatUnzip, concatUnzip3, zipFrom, zipWithFrom, zipWithLongest, replace, merge, mergeBy,+    lower, upper, trim, trimStart, trimEnd, word1, line1, escapeHTML, escapeJSON, unescapeHTML, unescapeJSON, dropEnd, takeEnd, splitAtEnd, breakEnd, spanEnd, dropWhileEnd', takeWhileEnd, stripSuffix, stripInfix, stripInfixEnd, dropPrefix, dropSuffix, wordsBy, linesBy, breakOn, breakOnEnd, splitOn, split, chunksOf, headDef, lastDef, (!?), notNull, list, unsnoc, cons, snoc, drop1, dropEnd1, mconcatMap, compareLength, comparingLength, enumerate, groupSort, groupSortOn, groupSortBy, nubOrd, nubOrdBy, nubOrdOn, nubOn, groupOn, nubSort, nubSortBy, nubSortOn, maximumOn, minimumOn, sum', product', sumOn', productOn', disjoint, disjointOrd, disjointOrdBy, allSame, anySame, repeatedly, firstJust, concatUnzip, concatUnzip3, zipFrom, zipWithFrom, zipWithLongest, replace, merge, mergeBy,     -- * Data.List.NonEmpty.Extra     -- | Extra functions available in @"Data.List.NonEmpty.Extra"@.     (|:), (|>), appendl, appendr, maximum1, minimum1, maximumBy1, minimumBy1, maximumOn1, minimumOn1,@@ -59,7 +59,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)+import Data.List.NonEmpty.Extra hiding (cons, snoc, sortOn, union, unionBy, nubOrd, nubOrdBy, nubOrdOn, (!?)) import Data.Tuple.Extra import Data.Version.Extra import Numeric.Extra
test/TestGen.hs view
@@ -4,8 +4,6 @@ {-# LANGUAGE ExtendedDefaultRules, ScopedTypeVariables, TypeApplications, ViewPatterns #-} module TestGen(tests) where import TestUtil-import qualified Data.List-import qualified Data.List.NonEmpty.Extra import qualified Data.Ord import Test.QuickCheck.Instances.Semigroup () default(Maybe Bool,Int,Double,Maybe (Maybe Bool),Maybe (Maybe Char))@@ -26,6 +24,8 @@     testGen "ignore (fail \"die\") == pure ()" $ ignore (fail "die") == pure ()     testGen "catch (errorIO \"Hello\") (\\(ErrorCall x) -> pure x) == pure \"Hello\"" $ catch (errorIO "Hello") (\(ErrorCall x) -> pure x) == pure "Hello"     testGen "seq (errorIO \"foo\") (print 1) == print 1" $ seq (errorIO "foo") (print 1) == print 1+    testGen "catch (assertIO True  >> pure 1) (\\(x :: AssertionFailed) -> pure 2) == pure 1" $ catch (assertIO True  >> pure 1) (\(x :: AssertionFailed) -> pure 2) == pure 1+    testGen "seq (assertIO False) (print 1) == print 1" $ seq (assertIO False) (print 1) == print 1     testGen "retry 1 (print \"x\")  == print \"x\"" $ retry 1 (print "x")  == print "x"     testGen "retry 3 (fail \"die\") == fail \"die\"" $ retry 3 (fail "die") == fail "die"     testGen "whenJust Nothing  print == pure ()" $ whenJust Nothing  print == pure ()@@ -107,6 +107,9 @@     testGen "lastDef 1 []      == 1" $ lastDef 1 []      == 1     testGen "lastDef 1 [2,3,4] == 4" $ lastDef 1 [2,3,4] == 4     testGen "\\x xs -> lastDef x xs == last (x:xs)" $ \x xs -> lastDef x xs == last (x:xs)+    testGen "[2,3,4] !? 1    == Just 3" $ [2,3,4] !? 1    == Just 3+    testGen "[2,3,4] !? (-1) == Nothing" $ [2,3,4] !? (-1) == Nothing+    testGen "[]      !? 0    == Nothing" $ []      !? 0    == Nothing     testGen "notNull []  == False" $ notNull []  == False     testGen "notNull [1] == True" $ notNull [1] == True     testGen "\\xs -> notNull xs == not (null xs)" $ \xs -> notNull xs == not (null xs)@@ -266,15 +269,6 @@     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     testGen "comparingLength [1,2] (1:2:3:undefined) == LT" $ comparingLength [1,2] (1:2:3:undefined) == LT     testGen "comparingLength (1:2:3:undefined) [1,2] == GT" $ comparingLength (1:2:3:undefined) [1,2] == GT-    testGen "(1 :| [2,3]) |> 4 |> 5 == 1 :| [2,3,4,5]" $ (1 :| [2,3]) |> 4 |> 5 == 1 :| [2,3,4,5]-    testGen "[1,2,3] |: 4 |> 5 == 1 :| [2,3,4,5]" $ [1,2,3] |: 4 |> 5 == 1 :| [2,3,4,5]-    testGen "appendl (1 :| [2,3]) [4,5] == 1 :| [2,3,4,5]" $ appendl (1 :| [2,3]) [4,5] == 1 :| [2,3,4,5]-    testGen "appendr [1,2,3] (4 :| [5]) == 1 :| [2,3,4,5]" $ appendr [1,2,3] (4 :| [5]) == 1 :| [2,3,4,5]-    testGen "(1 :| [3, 5, 3]) `union` (4 :| [5, 3, 5, 2]) == 1 :| [3, 5, 3, 4, 2]" $ (1 :| [3, 5, 3]) `union` (4 :| [5, 3, 5, 2]) == 1 :| [3, 5, 3, 4, 2]-    testGen "Data.List.NonEmpty.Extra.nubOrd (1 :| [2, 3, 3, 4, 1, 2]) == 1 :| [2, 3, 4]" $ Data.List.NonEmpty.Extra.nubOrd (1 :| [2, 3, 3, 4, 1, 2]) == 1 :| [2, 3, 4]-    testGen "\\xs -> Data.List.NonEmpty.Extra.nubOrd xs == Data.List.NonEmpty.Extra.nub xs" $ \xs -> Data.List.NonEmpty.Extra.nubOrd xs == Data.List.NonEmpty.Extra.nub xs-    testGen "Data.List.NonEmpty.Extra.nubOrdBy (compare `on` Data.List.length) (\"a\" :| [\"test\",\"of\",\"this\"]) == \"a\" :| [\"test\",\"of\"]" $ Data.List.NonEmpty.Extra.nubOrdBy (compare `on` Data.List.length) ("a" :| ["test","of","this"]) == "a" :| ["test","of"]-    testGen "Data.List.NonEmpty.Extra.nubOrdOn Data.List.length (\"a\" :| [\"test\",\"of\",\"this\"]) == \"a\" :| [\"test\",\"of\"]" $ Data.List.NonEmpty.Extra.nubOrdOn Data.List.length ("a" :| ["test","of","this"]) == "a" :| ["test","of"]     testGen "first succ (1,\"test\") == (2,\"test\")" $ first succ (1,"test") == (2,"test")     testGen "second reverse (1,\"test\") == (1,\"tset\")" $ second reverse (1,"test") == (1,"tset")     testGen "firstM (\\x -> [x-1, x+1]) (1,\"test\") == [(0,\"test\"),(2,\"test\")]" $ firstM (\x -> [x-1, x+1]) (1,"test") == [(0,"test"),(2,"test")]