toolshed 0.14.0.0 → 0.15.0.0
raw patch · 17 files changed
+411/−73 lines, 17 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- ToolShed.Test.SelfValidate: instance Arbitrary Primes
- ToolShed.Test.SelfValidate: instance Eq Primes
- ToolShed.Test.SelfValidate: instance Ord Primes
- ToolShed.Test.SelfValidate: instance SelfValidator Primes
- ToolShed.Test.SelfValidate: instance Show Primes
- ToolShed.Test.SelfValidate: quickChecks :: IO ()
+ ToolShed.Data.List: permutationsBy :: Matches a -> [[a]] -> [[a]]
+ ToolShed.Data.List: type Matches a = a -> a -> Bool
+ ToolShed.Data.Quadruple: curry4 :: ((a, b, c, d) -> result) -> a -> b -> c -> d -> result
+ ToolShed.Data.Quadruple: getFirst :: (a, b, c, d) -> a
+ ToolShed.Data.Quadruple: getFourth :: (a, b, c, d) -> d
+ ToolShed.Data.Quadruple: getSecond :: (a, b, c, d) -> b
+ ToolShed.Data.Quadruple: getThird :: (a, b, c, d) -> c
+ ToolShed.Data.Quadruple: uncurry4 :: (a -> b -> c -> d -> result) -> (a, b, c, d) -> result
+ ToolShed.Data.Triple: curry3 :: ((a, b, c) -> result) -> a -> b -> c -> result
+ ToolShed.Data.Triple: getFirst :: (a, b, c) -> a
+ ToolShed.Data.Triple: getSecond :: (a, b, c) -> b
+ ToolShed.Data.Triple: getThird :: (a, b, c) -> c
+ ToolShed.Data.Triple: uncurry3 :: (a -> b -> c -> result) -> (a, b, c) -> result
+ ToolShed.Defaultable: instance (Defaultable a, Defaultable b, Defaultable c) => Defaultable (a, b, c)
- ToolShed.Data.List: equalityBy :: Eq b => (a -> b) -> a -> a -> Bool
+ ToolShed.Data.List: equalityBy :: Eq b => (a -> b) -> Matches a
- ToolShed.Data.List: findConvergenceBy :: (a -> a -> Bool) -> [a] -> a
+ ToolShed.Data.List: findConvergenceBy :: Matches a -> [a] -> a
Files
- changelog +16/−8
- copyright +1/−1
- src/Main.hs +4/−8
- src/ToolShed/Data/Foldable.hs +1/−0
- src/ToolShed/Data/List.hs +50/−20
- src/ToolShed/Data/List/Runlength.hs +1/−0
- src/ToolShed/Data/Quadruple.hs +59/−0
- src/ToolShed/Data/Triple.hs +54/−0
- src/ToolShed/Defaultable.hs +3/−0
- src/ToolShed/System/File.hs +1/−1
- src/ToolShed/System/Random.hs +21/−17
- src/ToolShed/Test/Data/List.hs +15/−3
- src/ToolShed/Test/Data/Quadruple.hs +36/−0
- src/ToolShed/Test/Data/Triple.hs +37/−0
- src/ToolShed/Test/QuickChecks.hs +17/−7
- src/ToolShed/Test/System/Random.hs +82/−0
- toolshed.cabal +13/−8
changelog view
@@ -26,8 +26,7 @@ * Added functions 'merge' & 'mergeBy' to module "ToolShed.ListPlus" & exported a new type-synonym 'ToolShed.ListPlus.ChunkLength'. * Uploaded to <http://hackage.haskell.org/packages/hackage.html>. 0.12.0.0- * Added module "ToolShed.TimeAction" to measure the CPU-seconds required for an IO-action.- * Added module "Pair".+ * Added modules "ToolShed.TimeAction" to measure the CPU-seconds required for an IO-action, & "Pair". 0.12.0.1 * Removed unnecessary type-context 'Ord' from 'ToolShed.ListPus.mergeBy' & reimplemented 'ToolShed.ListPus.merge' in terms of 'ToolShed.ListPus.mergeBy'. * Added 'ToolShed.ListPlus.runLengthEncode' & 'ToolShed.ListPlus.runLengthDecode'.@@ -44,8 +43,7 @@ * Added instances of 'ToolShed.SelfValidate.SelfValidator' for 'Data.Maybe.Maybe' '(,)', 'Data.Set.Set', 'Data.Map.Map' & 'Data.Array.IArray.Array'. * Added instance of 'ToolShed.Defaultable.Defaultable' for '(,)'. * Added functions 'ToolShed.Data.List.showListWith', 'ToolShed.Data.List.permutations', 'ToolShed.Data.List.gatherBy', 'ToolShed.Data.List.findConvergenceBy', 'ToolShed.Data.List.findConvergence', 'ToolShed.Data.List.gather'.- * Added module "ToolShed.System.File".- * Added module "ToolShed.System.Random".+ * Added modules "ToolShed.System.File" & "ToolShed.System.Random". * Added method 'ToolShed.SelfValidate.getErrors', & supporting functions 'ToolShed.SelfValidate.getFirstErrors' & 'ToolShed.SelfValidate.extractErrors'. * Create module "ToolShed.Arbitrary.*". * Added "Main", "ToolShed.Test.QuickChecks" & "ToolShed.Test.Data.List" to facilitate testing.@@ -56,12 +54,22 @@ * Defined package's name using program's name, in "Main.hs". * Checked package "Base" exports 'Data.Tuple.swap', in "ToolShed.Arbitrary.Array". * Relocated "ToolShed.Arbitrary" to "ToolShed.Test.QuickCheck.Arbitrary".- * Added "ToolShed.Test.ReversibleBoundedEnum", "ToolShed.Test.ReversibleEnum" "ToolShed.Test.ReversibleIO", & "ToolShed.Test.SelfValidate".+ * Added "ToolShed.Test.ReversibleBoundedEnum", "ToolShed.Test.ReversibleEnum", "ToolShed.Test.ReversibleIO", & "ToolShed.Test.SelfValidate". * Amended 'ToolShed.System.File.locate' to deal with absolute file-paths. * Replaced legacy calls to 'Data.Map.fold' & 'Data.Set.fold', with more expicit calls to 'Data.Map.foldr' & 'Data.Set.foldr' from a more recent version of the "containers" package. * Added instance of 'ToolShed.SelfValidate.SelfValidator' for '(,,)'. * Trapped null list in 'ToolShed.System.Random.select'.- * Added "ToolShed.Data.List.nub'".- * Added 'ToolShed.Data.List.hasDuplicates'.+ * Added functions "ToolShed.Data.List.nub'" & 'ToolShed.Data.List.hasDuplicates'. * Migrated functions 'gather', 'gatherBy', 'hasDuplicates' which merely operate on 'Data.Foldable.Foldable' types from module "ToolShed.Data.List", into new module "ToolShed.Data.Foldable".-+0.15.0.0+ * Refactored 'ToolShed.Test.QuickChecks'.+ * Added type 'ToolShed.Data.List.Matches' & function 'ToolShed.Data.List.permutationsBy'.+ * Trapped the case of a null list supplied to 'ToolShed.Data.List.permutationsBy'.+ * Re-implemented 'ToolShed.System.Random.shuffle', using the Fisher-Yates algorithm; which also improved the efficiency.+ * Trapped special cases in 'ToolShed.System.Random.generateSelection'.+ * Added modules "ToolShed.Test.System.Random", "ToolShed.Data.Triple", "ToolShed.Data.Quadruple", "ToolShed.Test.Data.Triple", & "ToolShed.Test.Data.Quadruple".+ * Explicitly closed standard-input in the executable.+ * Replaced calls to 'error' from inside the IO-monad, with 'Control.Monad.fail'.+ * Added an instance for '(,,)', to "ToolShed.Defaultable.Defaultable".+ * Corrected version-string in "Main" used in '--version' option.+ * Corrected the output of 'Main.main.optDescrList.printVersion'.
copyright view
@@ -2,7 +2,7 @@ Dr. Alistair Ward <toolshed at functionalley dot eu>. Copyright:- Copyright (C) 2010-2011 Dr. Alistair Ward. All Rights Reserved.+ Copyright (C) 2010-2013 Dr. Alistair Ward. All Rights Reserved. Home-page: http://functionalley.eu
src/Main.hs view
@@ -24,13 +24,7 @@ * Facilitates testing. -} -module Main(--- * Types--- ** Type-synonyms--- CommandLineAction,--- * Functions- main-) where+module Main(main) where import qualified Data.List import qualified Data.Version@@ -52,6 +46,8 @@ -- | Parses the command-line arguments, to determine 'Test.CommandOptions.CommandOptions'. main :: IO () main = do+ System.IO.hClose System.IO.stdin --Nothing is read from standard input.+ progName <- System.Environment.getProgName let@@ -67,7 +63,7 @@ G.Option "q" ["runQuickChecks"] (G.NoArg $ const runQuickChecks) "Run Quick-checks using arbitrary data & then exit." ] where printVersion, printUsage, runQuickChecks :: IO ()- printVersion = System.IO.hPutStrLn System.IO.stderr (Distribution.Text.display packageIdentifier ++ "\n\nCopyright (C) 2011 " ++ author ++ ".\nThis program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it under certain conditions.\n\nWritten by " ++ author ++ ".") >> System.Exit.exitWith System.Exit.ExitSuccess where+ printVersion = System.IO.hPutStrLn System.IO.stderr (Distribution.Text.display packageIdentifier ++ "\n\nCopyright (C) 2010-2013 " ++ author ++ ".\nThis program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it under certain conditions.\n\nWritten by " ++ author ++ ".") >> System.Exit.exitWith System.Exit.ExitSuccess where packageIdentifier :: Distribution.Package.PackageIdentifier packageIdentifier = Distribution.Package.PackageIdentifier { Distribution.Package.pkgName = Distribution.Package.PackageName progName, --CAVEAT: coincidentally.
src/ToolShed/Data/Foldable.hs view
@@ -47,3 +47,4 @@ -- | Whether the specified collection contains any equal items. hasDuplicates :: (Data.Foldable.Foldable f, Ord a) => f a -> Bool hasDuplicates = any ((> 1) . length) . gather+
src/ToolShed/Data/List.hs view
@@ -24,6 +24,7 @@ -- * Types -- ** Type-synonyms ChunkLength,+ Matches, -- * Functions chunk, excise,@@ -36,6 +37,7 @@ nub', -- nubWithInt, permutations,+ permutationsBy, takeUntil, showListWith, -- showListWithChar,@@ -43,6 +45,7 @@ ) where import qualified Control.Arrow+import Control.Arrow((&&&)) import qualified Data.IntSet import qualified Data.List import qualified Data.Set@@ -51,17 +54,17 @@ type ChunkLength = Int {- |- * Splits a list into length-@size@ pieces, where @(size >= 0)@.+ * Splits a list into chunks of the specified length. - * The last chunk will be shorter, if @n@ isn't an aliquot part of the input list-length.+ * The last chunk will be shorter, if the chunk-length isn't an aliquot part of the input list-length. - * If @(size == 0)@, the resulting list will be an infinite sequence of null lists.+ * If the chunk-length is zero, the resulting list will be an infinite sequence of null lists. - * CAVEAT: a similar function is available in the module /Data.List.Split/, though this one checks for @(size < 0)@.+ * CAVEAT: a similar function is available in the module /Data.List.Split/, though this one checks for @(chunkLength < 0)@. -} chunk :: ChunkLength- -> [a] -- ^ The polymorphic input list to be chunked.+ -> [a] -- ^ The polymorphic input list to be chunked. -> [[a]] chunk size list | size < 0 = error $ "ToolShed.Data.List.chunk:\tnegative chunk-size=" ++ show size@@ -79,24 +82,60 @@ excise 0 = tail --Just for efficiency. excise i = uncurry (++) . Control.Arrow.second tail . splitAt i --- | A convenient way to compose the function-parameter required by 'Data.List.groupBy' or 'Data.List.nubBy'.-equalityBy :: Eq b => (a -> b) -> a -> a -> Bool+-- | The type of function required by 'findConvergenceBy', 'permutationsBy'.+type Matches a = a -> a -> Bool++-- | A convenient way to compose the 'Matches'-function required by 'findConvergenceBy' & 'permutationsBy'.+equalityBy :: Eq b => (a -> b) -> Matches a equalityBy f x y = f x == f y --- | Take the first element from the list, which compares equal according to the specified predicate, with the subsequent element.-findConvergenceBy :: (a -> a -> Bool) -> [a] -> a-findConvergenceBy predicate l = fst . head . dropWhile (not . uncurry predicate) . zip l $ tail l+-- | Take the first element from the (potentially infinite) list, which matches the subsequent element, according to the specified function.+findConvergenceBy :: Matches a -> [a] -> a+findConvergenceBy _ [] = error "ToolShed.Data.List.findConvergenceBy:\ta null list is too short for convergence to exist"+findConvergenceBy _ [_] = error "ToolShed.Data.List.findConvergenceBy:\ta singleton list is too short for convergence to exist"+findConvergenceBy matches l+ | null l' = error "ToolShed.Data.List.findConvergenceBy:\tno convergence found"+ | otherwise = fst $ head l'+ where+ l' = dropWhile (not . uncurry matches) . uncurry zip $ (init &&& tail) l -- | A specific instance of 'findConvergenceBy'. findConvergence :: Eq a => [a] -> a findConvergence = findConvergenceBy (==) +{- |+ * The list of all permutations, generated by selecting any one datum from each sub-list in turn, from the specified list of lists.++ * As each item is selected, the remaining lists are filtered according to the specified 'Matches'-function.++ * Thus '/=' could be used to select a different item from each list.+-}+permutationsBy :: Matches a -> [[a]] -> [[a]]+permutationsBy matches lists+ | any null lists = [] --Required for efficiency, to catch the case [bigList1, bigList2 ... null]+ | otherwise = slave lists+ where+ slave (xs : xss) = [x : xs' | x <- xs, xs' <- slave $ map (filter $ matches x) xss]+ slave [] = [[]]++{- |+ * The list of all permutations, generated by selecting any one datum from each sub-list in turn, from the specified list of lists.++ * A specific instance of 'permutationsBy', in which no filtering of subsequent lists is performed after each item is selected.++ * NB: differs from 'Data.List.permutations', which selects items from a single input list.+-}+permutations :: [[a]] -> [[a]]+permutations = permutationsBy (\_ _ -> True)+ {-# NOINLINE nub' #-} {-# RULES "nub'/Int" nub' = nubWithInt #-} {- |- * A version of 'Data.List.nub' with better time-complexity.+ * A strict version of 'Data.List.nub' with better time-complexity. + * CAVEAT: the specified list must be finite, since the entire set is constructed before streaming to a list.+ * CAVEAT: it sorts the output as a side-effect, & consequently it requires a type which implements 'Ord'. -} nub' :: Ord a => [a] -> [a]@@ -129,15 +168,6 @@ -- | A specific instance of 'mergeBy'. merge :: Ord a => [a] -> [a] -> [a] merge = mergeBy compare--{- |- * The list of all permutations, generated by selecting any one datum from each sub-list in turn, from the specified list of lists.-- * Taken from <http://www.haskell.org/pipermail/haskell-cafe/2006-June/015975.html>.--}-permutations :: [[a]] -> [[a]]-permutations (xs : xss) = [ x : xs' | x <- xs, xs' <- permutations xss ]-permutations [] = [[]] {- | * Take until the specified predicate is satisfied; /including/ the item which satisfied it.
src/ToolShed/Data/List/Runlength.hs view
@@ -53,3 +53,4 @@ -- | Performs /run-length/ decoding to retrieve the original unencoded list. decode :: [Code a] -> [a] decode = concatMap (uncurry replicate)+
+ src/ToolShed/Data/Quadruple.hs view
@@ -0,0 +1,59 @@+{-+ Copyright (C) 2013 Dr. Alistair Ward++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Miscellaneous operations on quadruples.++ [@CAVEAT@] Import fully qualified, since some identifiers clash with 'ToolShed.Data.Triple'.+-}++module ToolShed.Data.Quadruple(+-- * Functions+ curry4,+ uncurry4,+-- ** Accessors+ getFirst,+ getSecond,+ getThird,+ getFourth+) where++-- | Extends the concept of 'Data.Tuple.curry'.+curry4 :: ((a, b, c, d) -> result) -> a -> b -> c -> d -> result+curry4 f a b c d = f (a, b, c, d)++-- | Extends the concept of 'Data.Tuple.uncurry'.+uncurry4 :: (a -> b -> c -> d -> result) -> (a, b, c, d) -> result+uncurry4 f (a, b, c, d) = f a b c d++-- | Access the first datum from the specified quadruple.+getFirst :: (a, b, c, d) -> a+getFirst (a, _, _, _) = a++-- | Access the second datum from the specified quadruple.+getSecond :: (a, b, c, d) -> b+getSecond (_, b, _, _) = b++-- | Access the third datum from the specified quadruple.+getThird :: (a, b, c, d) -> c+getThird (_, _, c, _) = c++-- | Access the fourth datum from the specified quadruple.+getFourth :: (a, b, c, d) -> d+getFourth (_, _, _, d) = d+
+ src/ToolShed/Data/Triple.hs view
@@ -0,0 +1,54 @@+{-+ Copyright (C) 2013 Dr. Alistair Ward++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Miscellaneous operations on triples.++ [@CAVEAT@] Import fully qualified, since some identifiers clash with 'ToolShed.Data.Quadruple'.+-}++module ToolShed.Data.Triple(+-- * Functions+ curry3,+ uncurry3,+-- ** Accessors+ getFirst,+ getSecond,+ getThird+) where++-- | Extends the concept of 'Data.Tuple.curry'.+curry3 :: ((a, b, c) -> result) -> a -> b -> c -> result+curry3 f a b c = f (a, b, c)++-- | Extends the concept of 'Data.Tuple.uncurry'.+uncurry3 :: (a -> b -> c -> result) -> (a, b, c) -> result+uncurry3 f (a, b, c) = f a b c++-- | Access the first datum from the specified triple.+getFirst :: (a, b, c) -> a+getFirst (a, _, _) = a++-- | Access the second datum from the specified triple.+getSecond :: (a, b, c) -> b+getSecond (_, b, _) = b++-- | Access the third datum from the specified triple.+getThird :: (a, b, c) -> c+getThird (_, _, c) = c+
src/ToolShed/Defaultable.hs view
@@ -31,3 +31,6 @@ instance (Defaultable a, Defaultable b) => Defaultable (a, b) where defaultValue = (defaultValue, defaultValue)++instance (Defaultable a, Defaultable b, Defaultable c) => Defaultable (a, b, c) where+ defaultValue = (defaultValue, defaultValue, defaultValue)
src/ToolShed/System/File.hs view
@@ -103,5 +103,5 @@ case reads fileContents of [(x, _)] -> return {-to IO-monad-} (filePath, x) --CAVEAT: discards any unconsumed text.- _ -> error $ "ToolShed.System.File.fromFile:\tfailed to parse file=" ++ show filePath+ _ -> fail $ "ToolShed.System.File.fromFile:\tfailed to parse file=" ++ show filePath
src/ToolShed/System/Random.hs view
@@ -31,8 +31,8 @@ ) where import qualified Control.Arrow-import qualified Data.List-import qualified Data.Ord+import qualified Data.Sequence+import Data.Sequence((><), ViewL((:<))) import qualified System.Random -- | Constructs an infinite list of independent random-generators.@@ -40,37 +40,41 @@ randomGens = uncurry (:) . Control.Arrow.second randomGens {-recurse-} . System.Random.split {- |- * Shuffles the specified finite list.+ * Shuffles the specified finite list, using the /Fisher-Yates/ algorithm; <http://en.wikipedia.org/wiki/Fisher-Yates_shuffle>. * The resulting list has the same length and constituents as the original; only the order has changed. - * CAVEAT: the implementation /zips/ a list of integers, with the specified polymorphic list, then sorts it,- but when identical random integers are generated, the sort-algorithm being /stable/ always return the corresponding items in their original order.- The shuffle is therefore imperfect,- but on a /64-bit/ machine, it would need such a large list of items, for the probability of randomly generating two identical integers, to be significant,- that /sort/ probably wouldn't return in a reasonable time anyway.- Ideally, it would be amended to use an /unstable/ sort-algorithm.+ * The input list is traversed, but the items aren't evaluated. -} shuffle :: System.Random.RandomGen randomGen => randomGen -> [a] -> [a]-shuffle randomGen = map snd . Data.List.sortBy (Data.Ord.comparing fst) . zip (System.Random.randoms randomGen :: [Int])+shuffle _ [] = [] --Not strictly necessary.+shuffle _ singleton@[_] = singleton --Not strictly necessary.+shuffle randomGen l = slave randomGen s (pred $ Data.Sequence.length s) where+ s = Data.Sequence.fromList l + slave randomGen' s' maxIndex+ | maxIndex < 0 = []+ | otherwise = selection : slave randomGen'' (first >< remainder) (pred maxIndex) {-recurse-}+ where+ (randomIndex, randomGen'') = System.Random.randomR (0, maxIndex) randomGen'+ (first, selection :< remainder) = Control.Arrow.second Data.Sequence.viewl $ Data.Sequence.splitAt randomIndex s'+ {- |- * Generate an infinite list of items, each randomly selected from the specified finite list.+ * Generate an infinite list of items, each independently randomly selected from the specified finite list. * CAVEAT: because the selections are made non-destructively, duplicates may be returned; cf. 'shuffle'. -} generateSelection :: System.Random.RandomGen randomGen => randomGen -> [a] -> [a]+generateSelection _ [] = error "ToolShed.System.Random.generateSelection:\tnull list"+generateSelection _ [x] = repeat x --Not strictly necessary, but more efficient. generateSelection randomGen l = map (l !!) $ System.Random.randomRs (0, pred $ length l) randomGen --- | Return a random element from the specified list.+-- | Return a randomly selected element from the specified list. select :: System.Random.RandomGen randomGen => randomGen -> [a] -> a-select _ [] = error "ToolShed.System.Random.generateSelection:\tnull list"-select randomGen l = head $ generateSelection randomGen l+select randomGen = head . generateSelection randomGen {- |- * Generate an infinite list of items, each randomly selected, from the specified finite list of /bounded/ items.-- * Because the selections are made non-destructively, duplicates may be returned.+ * Generate an infinite list of data, each independently selected random instances of the specified /bounded/ type. * E.g. @ (generateSelectionFromBounded `fmap` System.Random.getStdGen) :: IO [Bool] @. -}
src/ToolShed/Test/Data/List.hs view
@@ -36,9 +36,9 @@ quickChecks :: IO () quickChecks = Test.QuickCheck.quickCheck prop_chunk- >> Test.QuickCheck.quickCheck prop_findConvergence+ >> Test.QuickCheck.quickCheck `mapM` [prop_findConvergence, prop_permutationsBy'] >> Test.QuickCheck.quickCheck prop_nub- >> Test.QuickCheck.quickCheck prop_permutations+ >> Test.QuickCheck.quickCheck `mapM` [prop_permutations, prop_permutations', prop_permutationsBy] >> Test.QuickCheck.quickCheck prop_linearise >> Test.QuickCheck.quickCheck prop_merge where@@ -51,9 +51,21 @@ prop_nub :: [Int] -> Test.QuickCheck.Property prop_nub x = Test.QuickCheck.label "prop_nub" $ ToolShed.Data.List.nub' x == Data.List.sort (Data.List.nub x) - prop_permutations :: [[Int]] -> Test.QuickCheck.Property+ prop_permutations, prop_permutations', prop_permutationsBy :: [[Int]] -> Test.QuickCheck.Property prop_permutations l = not (null l') ==> Test.QuickCheck.label "prop_permutations" $ length (ToolShed.Data.List.permutations l') == product (map length l') where l' = take 6 $ map (take 6) l --Limit the task.++ prop_permutations' l = not (null l') && all (not . null) l' ==> Test.QuickCheck.label "prop_permutations'" . (== 1) . length . Data.List.nub . map length $ ToolShed.Data.List.permutations l' where+ l' = take 7 $ map (take 5) l --Limit the task.++ prop_permutationsBy l = and [not $ null l', all (not . null) l', not $ null permutations] ==> Test.QuickCheck.label "prop_permutationsBy" . (== 1) . length . Data.List.nub $ map (length . Data.List.nub) permutations where+ l' = take 8 $ map (take 4) l --Limit the task.+ permutations = ToolShed.Data.List.permutationsBy (/=) l'++ prop_permutationsBy' :: Int -> Test.QuickCheck.Property+ prop_permutationsBy' i = Test.QuickCheck.label "prop_permutationsBy'" . all ((== range) . Data.List.sort) . ToolShed.Data.List.permutationsBy (/=) $ replicate (succ i') range where+ i' = succ $ mod i 7+ range = [0 .. i'] prop_linearise :: [(Int, Int)] -> Test.QuickCheck.Property prop_linearise l = Test.QuickCheck.label "prop_linearise" $ map (\[x, y] -> (x, y)) (ToolShed.Data.List.chunk 2 $ ToolShed.Data.List.linearise l) == l
+ src/ToolShed/Test/Data/Quadruple.hs view
@@ -0,0 +1,36 @@+{-+ Copyright (C) 2013 Dr. Alistair Ward++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Defines /QuickCheck/-properties "ToolShed.Data.Quadruple".+-}++module ToolShed.Test.Data.Quadruple(+-- * Functions+ quickChecks+) where++import qualified Test.QuickCheck+import qualified ToolShed.Data.Quadruple++-- | Defines invariant properties.+quickChecks :: IO ()+quickChecks = Test.QuickCheck.quickCheck prop_accessors where+ prop_accessors :: (Int, Char, Bool, Float) -> Test.QuickCheck.Property+ prop_accessors quadruple = Test.QuickCheck.label "prop_accessors" $ (f ToolShed.Data.Quadruple.getFirst quadruple, f ToolShed.Data.Quadruple.getSecond quadruple, f ToolShed.Data.Quadruple.getThird quadruple, ToolShed.Data.Quadruple.getFourth quadruple) == quadruple where+ f = ToolShed.Data.Quadruple.uncurry4 . ToolShed.Data.Quadruple.curry4
+ src/ToolShed/Test/Data/Triple.hs view
@@ -0,0 +1,37 @@+{-+ Copyright (C) 2013 Dr. Alistair Ward++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Defines /QuickCheck/-properties "ToolShed.Data.Triple".+-}++module ToolShed.Test.Data.Triple(+-- * Functions+ quickChecks+) where++import qualified Test.QuickCheck+import qualified ToolShed.Data.Triple++-- | Defines invariant properties.+quickChecks :: IO ()+quickChecks = Test.QuickCheck.quickCheck prop_accessors where+ prop_accessors :: (Int, Char, Bool) -> Test.QuickCheck.Property+ prop_accessors triple = Test.QuickCheck.label "prop_accessors" $ (f ToolShed.Data.Triple.getFirst triple, f ToolShed.Data.Triple.getSecond triple, f ToolShed.Data.Triple.getThird triple) == triple where+ f = ToolShed.Data.Triple.uncurry3 . ToolShed.Data.Triple.curry3+
src/ToolShed/Test/QuickChecks.hs view
@@ -25,17 +25,27 @@ run ) where +import qualified Control.Arrow import qualified ToolShed.Test.Data.Foldable import qualified ToolShed.Test.Data.List import qualified ToolShed.Test.Data.List.Runlength-import qualified ToolShed.Test.SelfValidate import qualified ToolShed.Test.Data.List.Splits+import qualified ToolShed.Test.Data.Quadruple+import qualified ToolShed.Test.Data.Triple+import qualified ToolShed.Test.SelfValidate+import qualified ToolShed.Test.System.Random -- | Run the /quickChecks/-functions for modules supporting this feature. run :: IO ()-run = putStrLn "Data.Foldable" >> ToolShed.Test.Data.Foldable.quickChecks- >> putStrLn "Data.List" >> ToolShed.Test.Data.List.quickChecks- >> putStrLn "Data.List.Runlength" >> ToolShed.Test.Data.List.Runlength.quickChecks- >> putStrLn "Data.List.Splits" >> ToolShed.Test.Data.List.Splits.quickChecks- >> putStrLn "SelfValidate" >> ToolShed.Test.SelfValidate.quickChecks-+run = mapM_ (+ uncurry (>>) . Control.Arrow.first putStrLn+ ) [+ ("Data.Foldable", ToolShed.Test.Data.Foldable.quickChecks),+ ("Data.List", ToolShed.Test.Data.List.quickChecks),+ ("Data.List.Runlength", ToolShed.Test.Data.List.Runlength.quickChecks),+ ("Data.List.Splits", ToolShed.Test.Data.List.Splits.quickChecks),+ ("Data.Quadruple", ToolShed.Test.Data.Quadruple.quickChecks),+ ("Data.Triple", ToolShed.Test.Data.Triple.quickChecks),+ ("SelfValidate", ToolShed.Test.SelfValidate.quickChecks),+ ("System.Random", ToolShed.Test.System.Random.quickChecks)+ ]
+ src/ToolShed/Test/System/Random.hs view
@@ -0,0 +1,82 @@+{-+ Copyright (C) 2013 Dr. Alistair Ward++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Defines /QuickCheck/-properties "ToolShed.System.Random".+-}++module ToolShed.Test.System.Random(+-- * Functions+-- getMean,+-- getStandardDeviation+ quickChecks+) where++import qualified Control.Arrow+import Control.Arrow((&&&),(***))+import qualified Data.Foldable+import qualified Data.List+import qualified Data.Map+import qualified System.Random+import qualified Test.QuickCheck+import qualified ToolShed.System.Random++-- | Determines the /mean/ of the specified numbers+getMean :: (Data.Foldable.Foldable f, Real r, Fractional result) => f r -> result+getMean = uncurry (/) . (realToFrac *** fromIntegral) . Data.Foldable.foldr (\i -> (+ i) *** succ) (0, 0 :: Int)++-- | Find the standard-deviation of the specified list.+getStandardDeviation :: (Data.Foldable.Foldable f, Functor f, Real r) => f r -> Double+getStandardDeviation x = sqrt . getMean $ fmap ((^ (2 :: Int)) . (+ negate (getMean x :: Rational)) . toRational) x++-- | Defines invariant properties.+quickChecks :: IO ()+quickChecks+ = Test.QuickCheck.quickCheck prop_shuffle+ >> Test.QuickCheck.quickCheck prop_shuffleDistribution+ where+ prop_shuffle :: Int -> Int -> Test.QuickCheck.Property+ prop_shuffle seed l = Test.QuickCheck.label "prop_shuffle" . (== testList) . Data.List.sort $ ToolShed.System.Random.shuffle (System.Random.mkStdGen seed) testList where+ testList = [0 .. l `mod` 10000]++ prop_shuffleDistribution :: Int -> Test.QuickCheck.Property+ prop_shuffleDistribution = Test.QuickCheck.label "prop_shuffleDistribution" . all (+ uncurry (&&) . (+ (+ < recip 20 {-empirically-} --The ideal value for a uniform distribution, would be zero.+ ) . (+ / getStandardDeviation (populationSize : replicate (pred $ length testList) 0) --Normalise wrt the worst-case; which occurs when this column contains the same letter, for each test-case in the population.+ ) . getStandardDeviation &&& (+ == populationSize --Confirm the size of the test-data.+ ) . Data.Foldable.sum+ )+ ) . map (+ foldr (+ uncurry $ Data.Map.insertWith (+)+ ) (+ Data.Map.fromList . zip testList $ repeat (0 :: Int) --Initial value.+ ) . (`zip` repeat 1) --Count the instances of each letter in this column, which for a uniform distribution, should be approximately the same.+ ) . Data.List.transpose {-examine the columns-} . take populationSize . map fst {-shuffled digits-} . tail {-drop initial value-} . iterate (+ Control.Arrow.first (`ToolShed.System.Random.shuffle` testList) . System.Random.split . snd+ ) . (,) undefined . System.Random.mkStdGen where+ testList :: String+ testList = ['a' .. 'z']++ populationSize :: Int+ populationSize = 1000+
toolshed.cabal view
@@ -1,8 +1,8 @@ --Package-properties Name: toolshed-Version: 0.14.0.0+Version: 0.15.0.0 Cabal-Version: >= 1.6-Copyright: (C) 2010 Dr. Alistair Ward+Copyright: (C) 2010-2013 Dr. Alistair Ward License: GPL License-file: LICENSE Author: Dr. Alistair Ward@@ -11,7 +11,7 @@ Build-Type: Simple Description: An ill-defined collection of simple unrelated utilities used by other packages from <http://functionalley.eu> Category: Utils-Tested-With: GHC == 6.10, GHC == 6.12, GHC == 7.0, GHC == 7.4+Tested-With: GHC == 7.4 Homepage: http://functionalley.eu Maintainer: toolshed <at> functionalley <dot> eu Bug-reports: toolshed <at> functionalley <dot> eu@@ -35,6 +35,8 @@ ToolShed.Data.List.Runlength ToolShed.Data.List.Splits ToolShed.Data.Pair+ ToolShed.Data.Quadruple+ ToolShed.Data.Triple ToolShed.Defaultable ToolShed.Options ToolShed.SelfValidate@@ -42,14 +44,13 @@ ToolShed.System.Random ToolShed.System.TimeAction ToolShed.System.TimePure- ToolShed.Test.ReversibleBoundedEnum- ToolShed.Test.ReversibleEnum- ToolShed.Test.ReversibleIO- ToolShed.Test.SelfValidate ToolShed.Test.QuickCheck.Arbitrary.Array ToolShed.Test.QuickCheck.Arbitrary.ArrayElem ToolShed.Test.QuickCheck.Arbitrary.Map ToolShed.Test.QuickCheck.Arbitrary.Set+ ToolShed.Test.ReversibleBoundedEnum+ ToolShed.Test.ReversibleEnum+ ToolShed.Test.ReversibleIO Build-depends: array,@@ -80,11 +81,15 @@ Main-Is: Main.hs Other-modules:- ToolShed.Test.QuickChecks ToolShed.Test.Data.Foldable ToolShed.Test.Data.List ToolShed.Test.Data.List.Runlength ToolShed.Test.Data.List.Splits+ ToolShed.Test.Data.Quadruple+ ToolShed.Test.Data.Triple+ ToolShed.Test.QuickChecks+ ToolShed.Test.SelfValidate+ ToolShed.Test.System.Random Build-depends: Cabal >= 1.6 && < 2