packages feed

toolshed 0.12.0.0 → 0.13.0.0

raw patch · 28 files changed

+1197/−415 lines, 28 filesdep +Cabaldep +QuickCheckdep +arraynew-component:exe:toolshedPVP ok

version bump matches the API change (PVP)

Dependencies added: Cabal, QuickCheck, array, containers, directory, filepath, random

API changes (from Hackage documentation)

- ToolShed.ListPlus: chunk :: ChunkLength -> [a] -> [[a]]
- ToolShed.ListPlus: excise :: Int -> [a] -> [a]
- ToolShed.ListPlus: groupComparing :: Eq b => (a -> b) -> [a] -> [[a]]
- ToolShed.ListPlus: linearise :: [(a, a)] -> [a]
- ToolShed.ListPlus: merge :: Ord a => [a] -> [a] -> [a]
- ToolShed.ListPlus: mergeBy :: Ord a => (a -> a -> Ordering) -> [a] -> [a] -> [a]
- ToolShed.ListPlus: splitsLeftFrom :: Int -> [a] -> [Split a]
- ToolShed.ListPlus: splitsRightFrom :: Int -> [a] -> [Split a]
- ToolShed.ListPlus: takeUntil :: (a -> Bool) -> [a] -> [a]
- ToolShed.ListPlus: type ChunkLength = Int
- ToolShed.Pair: both :: (Bool, Bool) -> Bool
- ToolShed.Pair: mirror :: (a -> b) -> (a, a) -> (b, b)
- ToolShed.Pair: neither :: (Bool, Bool) -> Bool
- ToolShed.SelfValidate: instance SelfValidator a => SelfValidator [a]
- ToolShed.TimeAction: getCPUSeconds :: Fractional seconds => IO result -> IO (seconds, result)
- ToolShed.TimeAction: printCPUSeconds :: IO result -> IO result
- ToolShed.TimePure: getCPUSeconds :: (Fractional seconds, NFData expression) => expression -> IO (seconds, expression)
- ToolShed.TimePure: printCPUSeconds :: NFData expression => expression -> IO expression
- ToolShed.Unsafe: print' :: Show s => s -> s
- ToolShed.Unsafe: printShow :: Show s => String -> s -> s
+ ToolShed.Arbitrary.Array: instance (Ix i, Enum i, Arbitrary i, Arbitrary e) => Arbitrary (Array i e)
+ ToolShed.Arbitrary.ArrayElem: instance (Bounded i, Ix i, Enum i, Arbitrary e) => Arbitrary (Array i e)
+ ToolShed.Arbitrary.Map: instance (Ord k, Arbitrary k, Arbitrary v) => Arbitrary (Map k v)
+ ToolShed.Arbitrary.Set: instance (Ord k, Arbitrary k) => Arbitrary (Set k)
+ ToolShed.Data.List: chunk :: ChunkLength -> [a] -> [[a]]
+ ToolShed.Data.List: equalityBy :: Eq b => (a -> b) -> a -> a -> Bool
+ ToolShed.Data.List: excise :: Int -> [a] -> [a]
+ ToolShed.Data.List: findConvergence :: Eq a => [a] -> a
+ ToolShed.Data.List: findConvergenceBy :: (a -> a -> Bool) -> [a] -> a
+ ToolShed.Data.List: gather :: (Foldable f, Ord a) => f a -> [[a]]
+ ToolShed.Data.List: gatherBy :: (Foldable f, Ord b) => (a -> b) -> f a -> [[a]]
+ ToolShed.Data.List: linearise :: [(a, a)] -> [a]
+ ToolShed.Data.List: merge :: Ord a => [a] -> [a] -> [a]
+ ToolShed.Data.List: mergeBy :: (a -> a -> Ordering) -> [a] -> [a] -> [a]
+ ToolShed.Data.List: permutations :: [[a]] -> [[a]]
+ ToolShed.Data.List: showListWith :: (Show token, Show element) => (token, token, token) -> [element] -> ShowS
+ ToolShed.Data.List: takeUntil :: (a -> Bool) -> [a] -> [a]
+ ToolShed.Data.List: type ChunkLength = Int
+ ToolShed.Data.List.Runlength: decode :: [Code a] -> [a]
+ ToolShed.Data.List.Runlength: encode :: Eq a => [a] -> [Code a]
+ ToolShed.Data.List.Runlength: getDatum :: Code a -> a
+ ToolShed.Data.List.Runlength: getLength :: Code a -> Int
+ ToolShed.Data.List.Runlength: type Code a = (Int, a)
+ ToolShed.Data.List.Splits: splitsLeftFrom :: Int -> [a] -> [Split a]
+ ToolShed.Data.List.Splits: splitsRightFrom :: Int -> [a] -> [Split a]
+ ToolShed.Data.Pair: mirror :: (a -> b) -> (a, a) -> (b, b)
+ ToolShed.Defaultable: instance (Defaultable a, Defaultable b) => Defaultable (a, b)
+ ToolShed.SelfValidate: extractErrors :: [(Bool, String)] -> [String]
+ ToolShed.SelfValidate: getErrors :: SelfValidator v => v -> [String]
+ ToolShed.SelfValidate: getFirstError :: SelfValidator v => v -> String
+ ToolShed.SelfValidate: instance (Ix index, SelfValidator element) => SelfValidator (Array index element)
+ ToolShed.SelfValidate: instance (SelfValidator a, SelfValidator b) => SelfValidator (a, b)
+ ToolShed.SelfValidate: instance SelfValidator v => SelfValidator (Map k v)
+ ToolShed.SelfValidate: instance SelfValidator v => SelfValidator (Maybe v)
+ ToolShed.SelfValidate: instance SelfValidator v => SelfValidator (Set v)
+ ToolShed.SelfValidate: instance SelfValidator v => SelfValidator [v]
+ ToolShed.System.File: fromFile :: Read a => FilePath -> SearchPath -> IO (LocatedData a)
+ ToolShed.System.File: getData :: LocatedData a -> a
+ ToolShed.System.File: getFile :: FilePath -> SearchPath -> IO (LocatedData String)
+ ToolShed.System.File: getFilePath :: LocatedData a -> FilePath
+ ToolShed.System.File: locate :: FilePath -> SearchPath -> IO [FilePath]
+ ToolShed.System.File: type LocatedData a = (FilePath, a)
+ ToolShed.System.File: type SearchPath = [FilePath]
+ ToolShed.System.Random: generateSelection :: RandomGen randomGen => randomGen -> [a] -> [a]
+ ToolShed.System.Random: generateSelectionFromBounded :: (RandomGen randomGen, Bounded a, Random a) => randomGen -> [a]
+ ToolShed.System.Random: randomGens :: RandomGen randomGen => randomGen -> [randomGen]
+ ToolShed.System.Random: select :: RandomGen randomGen => randomGen -> [a] -> a
+ ToolShed.System.Random: shuffle :: RandomGen randomGen => randomGen -> [a] -> [a]
+ ToolShed.System.TimeAction: getCPUSeconds :: Fractional seconds => IO result -> IO (seconds, result)
+ ToolShed.System.TimeAction: printCPUSeconds :: IO result -> IO result
+ ToolShed.System.TimePure: getCPUSeconds :: (Fractional seconds, NFData expression) => expression -> IO (seconds, expression)
+ ToolShed.System.TimePure: printCPUSeconds :: NFData expression => expression -> IO expression
- ToolShed.SelfValidate: class SelfValidator a
+ ToolShed.SelfValidate: class SelfValidator v where isValid = null . getErrors
- ToolShed.SelfValidate: isValid :: SelfValidator a => a -> Bool
+ ToolShed.SelfValidate: isValid :: SelfValidator v => v -> Bool

Files

changelog view
@@ -28,3 +28,27 @@ 0.12.0.0 	* Added module "ToolShed.TimeAction" to measure the CPU-seconds required for an IO-action. 	* Added module "Pair".+0.12.0.1+	* Removed unnecessary type-context 'Ord' from 'ToolShed.ListPus.mergeBy' and reimplemented 'ToolShed.ListPus.merge' in terms of 'ToolShed.ListPus.mergeBy'.+	* Added 'ToolShed.ListPlus.runLengthEncode' and 'ToolShed.ListPlus.runLengthDecode'.+0.13.0.0+	* Removed module "ToolShed.Unsafe".+	* Renamed:+		"ToolShed.ListPlus" to "ToolShed.Data.List"+		"ToolShed.Pair" to "ToolShed.Data.Pair"+		"ToolShed.TimeAction" to "ToolShed.System.TimeAction"+		"ToolShed.TimePure" to "ToolShed.System.TimePure"+	* Migrated 'ToolShed.Data.List.RunLengthCode' and associated functions, into a new module "ToolShed.Data.List.Runlength".+	* Migrated 'ToolShed.Data.List.Splits' and associated functions, into a new module "ToolShed.Data.List.Splits".+	* Replaced function 'ToolShed.Data.List.groupComparing' with the more useful 'ToolShed.Data.List.equalityBy', which can be used with either 'Data.List.groupBy' or 'Data.List.nubBy'.+	* Added instances of 'ToolShed.SelfValidate.SelfValidator' for 'Data.Maybe.Maybe' '(,)', 'Data.Set.Set', 'Data.Map.Map' and '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 method 'ToolShed.SelfValidate.getErrors', and supporting functions 'ToolShed.SelfValidate.getFirstErrors' and 'ToolShed.SelfValidate.extractErrors'.+	* Create module "ToolShed.Arbitrary.*".+	* Added "Main", "ToolShed.Test.QuickChecks" and "ToolShed.Test.Data.List" to facilitate testing.+	* Removed 'ToolShed.Data.Pair.both'.+	* Replaced "System" with "System.Environment" and "System.Exit".+	* Removed dependency on "haskell98".
makefile view
@@ -1,18 +1,18 @@ # Copyright (C) 2010 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/>.- + .PHONY: all build check clean configure copy haddock help hlint install prof sdist  all: install@@ -50,7 +50,7 @@  clean: 	runhaskell Setup.hs $@-	find src -type f \( -name '*.o' -o -name '*.hi' \) -delete+	find src -type f \( -name '*.hc' -o -name '*.hcr' -o -name '*.hi' -o -name '*.o' \) -delete  help: 	@grep '^[a-zA-Z].*:' makefile | sed -e 's/:.*//'
+ src/Main.hs view
@@ -0,0 +1,85 @@+{-+	Copyright (C) 2012 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@]++	* Contains the entry-point to the program.++	* Facilitates testing.+-}++module Main(+-- * Types+-- ** Type-synonyms+--	CommandLineAction,+-- * Functions+	main+) where++import qualified	Data.List+import qualified	Data.Version+import qualified	Distribution.Package+import qualified	Distribution.Text+import qualified	Distribution.Version+import qualified	Paths_toolshed		as Paths	--Either local stub, or package-instance autogenerated by 'Setup.hs build'.+import qualified	System.Console.GetOpt	as G+import qualified	System.Environment+import qualified	System.Exit+import qualified	System.IO+import qualified	System.IO.Error+import qualified	ToolShed.Defaultable+import qualified	ToolShed.Test.QuickChecks++-- | Used to thread user-defined command-line options, though the list of functions which implement them.+type CommandLineAction	= () -> IO ()	--Supplied as the type-argument to 'G.OptDescr'.++-- | Parses the command-line arguments, to determine 'Test.CommandOptions.CommandOptions'.+main :: IO ()+main	= do+	progName	<- System.Environment.getProgName+	args		<- System.Environment.getArgs++	let+		usage :: String+		usage	= "Usage:\t" ++ G.usageInfo progName optDescrList++--Define the command-line options, and the 'CommandLineAction's used to handle them.+		optDescrList :: [G.OptDescr CommandLineAction]+		optDescrList	= [+--				 String	[String]		(G.ArgDescr CommandLineAction)												String+			G.Option "?"	["help"]		(G.NoArg $ const printUsage)												"Display this help-text & then exit.",+			G.Option ""	["version"]		(G.NoArg $ const printVersion)												"Print version-information & then exit.",+			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 Dr. Alistair Ward.\nThis program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it under certain conditions.\n\nWritten by Dr. Alistair Ward.")	>> System.Exit.exitWith System.Exit.ExitSuccess	where+				packageIdentifier :: Distribution.Package.PackageIdentifier+				packageIdentifier	= Distribution.Package.PackageIdentifier {+					Distribution.Package.pkgName	= Distribution.Package.PackageName "toolshed",+					Distribution.Package.pkgVersion	= Distribution.Version.Version (Data.Version.versionBranch Paths.version) []+				}++			printUsage	= System.IO.hPutStrLn System.IO.stderr usage	>> System.Exit.exitWith System.Exit.ExitSuccess+			runQuickChecks	= ToolShed.Test.QuickChecks.run			>> System.Exit.exitWith System.Exit.ExitSuccess++--	G.getOpt :: G.ArgOrder CommandLineAction -> [G.OptDescr Action] -> [String] -> ([Action], [String], [String])+	case G.getOpt G.RequireOrder optDescrList args of+		(commandLineActions, _, [])	-> Data.List.foldl' (>>=) (return {-to IO-monad-} ()) commandLineActions	>> System.Exit.exitWith System.Exit.ExitSuccess+		(_, _, errors)			-> System.IO.Error.ioError . System.IO.Error.userError $ concat errors ++ usage	--Throw.+
+ src/ToolShed/Arbitrary/Array.hs view
@@ -0,0 +1,52 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+	Copyright (C) 2012 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@]	Implements 'Test.QuickCheck.Arbitrary' for 'Data.Array.IArray.Array'.++ [@EXAMPLE@]	@Test.QuickCheck.sample (Test.QuickCheck.arbitrary :: Test.QuickCheck.Gen.Gen (Data.Array.IArray.Array Char Int))@++ [@CAVEAT@]	An array with arbitrary indices isn't very useful.+-}++module ToolShed.Arbitrary.Array() where++import			Control.Applicative((<$>))+import qualified	Data.Array.IArray+import qualified	Data.Tuple+import qualified	Test.QuickCheck++instance (Data.Array.IArray.Ix i, Enum i, Test.QuickCheck.Arbitrary i, Test.QuickCheck.Arbitrary e) => Test.QuickCheck.Arbitrary (Data.Array.IArray.Array i e)	where+	arbitrary	= do+		pair	<- Test.QuickCheck.arbitrary {-(i, i)-}++		let+			bounds@(lower, upper)+				| uncurry (>) pair	= Data.Tuple.swap pair+				| otherwise		= pair++			indices	= [lower .. upper]++		Data.Array.IArray.array bounds . zip indices <$> Test.QuickCheck.vector (length indices)++#if !(MIN_VERSION_QuickCheck(2,1,0))+	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.+#endif+
+ src/ToolShed/Arbitrary/ArrayElem.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+	Copyright (C) 2012 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@]++	Implements 'Test.QuickCheck.Arbitrary' for 'Data.Array.IArray.Array',+	where the array-index is required to be a /bounded enumerable/ type.++ [@EXAMPLE@]	@Test.QuickCheck.sample (Test.QuickCheck.arbitrary :: Test.QuickCheck.Gen.Gen (Data.Array.IArray.Array Data.Int.Int8 Int))@+-}++module ToolShed.Arbitrary.ArrayElem() where++import			Control.Applicative((<$>))+import qualified	Data.Array.IArray+import qualified	Test.QuickCheck++instance (Bounded i, Data.Array.IArray.Ix i, Enum i, Test.QuickCheck.Arbitrary e) => Test.QuickCheck.Arbitrary (Data.Array.IArray.Array i e)	where+	arbitrary	= Data.Array.IArray.array bounds . zip [minBound .. maxBound] <$> Test.QuickCheck.vector (succ $ fromEnum (snd bounds) - fromEnum (fst bounds))	where+		bounds	= (minBound, maxBound)++#if !(MIN_VERSION_QuickCheck(2,1,0))+	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.+#endif+
+ src/ToolShed/Arbitrary/Map.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+	Copyright (C) 2012 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@]	Implements 'Test.QuickCheck.Arbitrary' for 'Data.Map.Map'.++ [@EXAMPLE@]	@Test.QuickCheck.sample (Test.QuickCheck.arbitrary :: Test.QuickCheck.Gen.Gen (Data.Map.Map Char Int))@+-}++module ToolShed.Arbitrary.Map() where++import			Control.Applicative((<$>))+import qualified	Data.Map+import qualified	Test.QuickCheck++instance (Ord k, Test.QuickCheck.Arbitrary k, Test.QuickCheck.Arbitrary v) => Test.QuickCheck.Arbitrary (Data.Map.Map k v)	where+	arbitrary	= Data.Map.fromList <$> Test.QuickCheck.arbitrary {-[(k, v)]-}++#if !(MIN_VERSION_QuickCheck(2,1,0))+	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.+#endif+
+ src/ToolShed/Arbitrary/Set.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+	Copyright (C) 2012 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@]	Implements 'Test.QuickCheck.Arbitrary' for 'Data.Set.Set'.++ [@EXAMPLE@]	@Test.QuickCheck.sample (Test.QuickCheck.arbitrary :: Test.QuickCheck.Gen.Gen (Data.Set.Set Int))@+-}++module ToolShed.Arbitrary.Set() where++import			Control.Applicative((<$>))+import qualified	Data.Set+import qualified	Test.QuickCheck++instance (Ord k, Test.QuickCheck.Arbitrary k) => Test.QuickCheck.Arbitrary (Data.Set.Set k)	where+	arbitrary	= Data.Set.fromList <$> Test.QuickCheck.arbitrary {-[k]-}++#if !(MIN_VERSION_QuickCheck(2,1,0))+	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.+#endif+
+ src/ToolShed/Data/List.hs view
@@ -0,0 +1,171 @@+{-+	Copyright (C) 2010 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 polymorphic list-operations.+-}++module ToolShed.Data.List(+-- * Types+-- ** Type-synonyms+	ChunkLength,+-- * Functions+	chunk,+	excise,+	equalityBy,+	findConvergence,+	findConvergenceBy,+	gather,+	gatherBy,+	linearise,+	merge,+	mergeBy,+	permutations,+	takeUntil,+	showListWith,+--	showListWithChar+--	showListWithString+) where++import qualified	Control.Arrow+import qualified	Data.Foldable+import qualified	Data.List+import qualified	Data.Map+--import qualified	Data.Ord++-- | The length of the chunks into which a list is split.+type ChunkLength	= Int++{- |+	* Splits a list into length-@size@ pieces, where @(size >= 0)@.++	* The last chunk will be shorter, if @n@ isn't an aliquot part of the input list-length.++	* If @(size == 0)@, 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)@.+-}+chunk+	:: ChunkLength+	-> [a]		-- ^ The polymorphic input list to be chunked.+	-> [[a]]+chunk size list+	| size < 0	= error $ "ToolShed.Data.List.chunk:\tnegative chunk-size=" ++ show size+	| otherwise	= chunk' list+	where+		chunk' :: [a] -> [[a]]+		chunk' []	= []+		chunk' a	= uncurry (:) . Control.Arrow.second chunk' $ splitAt size a++-- | Remove the single indexed element from the list.+excise+	:: Int	-- ^ The index.+	-> [a]	-- ^ The polymorphic input list.+	-> [a]	-- ^ The same list, with the indexed element removed.+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+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++-- | A specific instance of 'findConvergenceBy'.+findConvergence :: Eq a => [a] -> a+findConvergence	= findConvergenceBy (==)++{- |+	* Group equal (though not necessarily adjacent) elements, according to the specified comparator.++	* The groups are returned in ascending order, whilst their elements remain in their original order.+-}+gatherBy :: (Data.Foldable.Foldable f, Ord b) => (a -> b) -> f a -> [[a]]+gatherBy f	= Data.Map.elems . Data.Foldable.foldr (\x -> Data.Map.insertWith (++) (f x) [x]) Data.Map.empty++-- | A specific instance of 'gatherBy'.+gather :: (Data.Foldable.Foldable f, Ord a) => f a -> [[a]]+gather	= gatherBy id++-- | Converts a list of /Pairs/, into a narrower list.+linearise :: [(a, a)] -> [a]+linearise []			= []+linearise ((l, r) : remainder)	= l : r : linearise remainder	--Recurse.++{- |+	* Merge two sorted lists, according to the specified order, to product a single sorted list.++	* The merge-process is /stable/, in that where items from each list are equal, they remain in the original order.++	* CAVEAT: duplicates are preserved.+-}+mergeBy :: (a -> a -> Ordering) -> [a] -> [a] -> [a]+mergeBy cmp	= slave	where+	slave l@(x : xs) r@(y : ys)+		| x `cmp` y == GT	= y : slave l ys+		| otherwise		= x : slave xs r+	slave [] r	= r+	slave l []	= l++-- | 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.++	* NB: @takeWhile (not . test)@ would return one fewer item.+-}+takeUntil+	:: (a -> Bool)	-- ^ Predicate, used to determine the last item taken.+	-> [a]		-- ^ The polymorphic input list.+	-> [a]+takeUntil predicate	= takeUntil'	where+	takeUntil' (x : xs)	= x {-take regardless-} : if predicate x then [] else takeUntil' xs+	takeUntil' _		= []++-- | Show a list, delimited by the specified tokens.+showListWith :: (Show token, Show element)+	=> (token, token, token)	-- ^ (Start-delimiter, separator, end-delimiter)+	-> [element]			-- ^ The polymorphic list to show.+	-> ShowS+showListWith (startDelimiter, separator, endDelimiter)	= foldr (.) (shows endDelimiter) . (shows startDelimiter :) . Data.List.intersperse (shows separator) . map shows++{-# NOINLINE showListWith #-}+{-# RULES "showListWith/Char" showListWith = showListWithChar #-}+{-# RULES "showListWith/String" showListWith = showListWithString #-}++-- | A specialisation of 'showListWith'.+showListWithChar :: Show element => (Char, Char, Char) -> [element] -> ShowS+showListWithChar (startDelimiter, separator, endDelimiter)	= foldr (.) (showChar endDelimiter) . (showChar startDelimiter :) . Data.List.intersperse (showChar separator) . map shows++-- | A specialisation of 'showListWith'.+showListWithString :: Show element => (String, String, String) -> [element] -> ShowS+showListWithString (startDelimiter, separator, endDelimiter)	= foldr (.) (showString endDelimiter) . (showString startDelimiter :) . Data.List.intersperse (showString separator) . map shows+
+ src/ToolShed/Data/List/Runlength.hs view
@@ -0,0 +1,55 @@+{-+	Copyright (C) 2010 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@]	Run-length encoder and decoder.+-}++module ToolShed.Data.List.Runlength(+-- * Types+-- ** Type-synonyms+	Code,+-- * Functions+	encode,+	decode,+-- ** Accessors+	getLength,+	getDatum+) where++import			Control.Arrow((&&&))+import qualified	Data.List++-- | Describes the number of consecutive equal items in a list.+type Code a	= (Int, a)++-- | Accessor.+getLength :: Code a -> Int+getLength	= fst++-- | Accessor.+getDatum :: Code a -> a+getDatum	= snd++-- | /Run-length/ encodes the specified list.+encode :: Eq a => [a] -> [Code a]+encode	= map (length &&& head) . Data.List.group++-- | Performs /run-length/ decoding to retrieve the original unencoded list.+decode :: [Code a] -> [a]+decode	= concatMap (uncurry replicate)
+ src/ToolShed/Data/List/Splits.hs view
@@ -0,0 +1,66 @@+{-+	Copyright (C) 2010 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@]+-}++module ToolShed.Data.List.Splits(+-- * Types+-- ** Type-synonyms+--	Split,+-- * Functions+--	splitsFrom,+	splitsLeftFrom,+	splitsRightFrom+) where++-- | The polymorphic pair, resulting from splitting a list of arbitrary type.+type Split a	= ([a] {-left list-}, [a] {-right list-})++-- | Use the specified transformation, to generate a list of 'Split's, from the initial one.+splitsFrom+	:: (Split a -> Split a)	-- ^ The function used to transform one /split/ into the next.+	-> Int			-- ^ Index.+	-> [a]			-- ^ The polymorphic input list from which the /splits/ are generated.+	-> [Split a]		-- ^ The list of all required splits of the single input list.+splitsFrom transformation i+	| i < 0		= error $ "ToolShed.Data.List.Splits.splitsFrom:\tnegative starting-index; " ++ show i+	| otherwise	= iterate transformation . splitAt i++{- |+	* Create the set of all 'Split's, migrating left from the specified location.++	* CAVEAT: 'init' fails when 'fst' has been reduced to null.+-}+splitsLeftFrom+	:: Int		-- ^ Index.+	-> [a]		-- ^ The polymorphic input list from which the /splits/ are generated, as the index is stepped left+	-> [Split a]	-- ^ The list of all required splits of the single input list.+splitsLeftFrom	= splitsFrom (\(l, r) -> (init l, last l : r))++{- |+	* Create the set of all 'Split's, migrating right from the specified location.++	* CAVEAT: pattern-match against @ : @ fails, when 'snd' has been reduced to 'null'.+-}+splitsRightFrom+	:: Int		-- ^ Index.+	-> [a]		-- ^ The polymorphic input list from which the /splits/ are generated, as the index is stepped right.+	-> [Split a]	-- ^ The list of all required splits of the single input list.+splitsRightFrom	= splitsFrom (\(l, r : rs) -> (l ++ [r], rs))
+ src/ToolShed/Data/Pair.hs view
@@ -0,0 +1,37 @@+{-+	Copyright (C) 2010 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 Pairs.+-}++module ToolShed.Data.Pair(+-- * Functions+	mirror+) where++import	Control.Arrow((***))++{- |+	* Apply the same transformation to both halves of a /Pair/.++	* CAVEAT: the pair is required to have identical types.+-}+mirror :: (a -> b) -> (a, a) -> (b, b)+mirror f	= f *** f+
src/ToolShed/Defaultable.hs view
@@ -29,3 +29,5 @@ class Defaultable a	where 	defaultValue	:: a	-- ^ The default value of the data-type. +instance (Defaultable a, Defaultable b) => Defaultable (a, b)	where+	defaultValue	= (defaultValue, defaultValue)
− src/ToolShed/ListPlus.hs
@@ -1,168 +0,0 @@-{--	Copyright (C) 2010 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 polymorphic list-operations.--}--module ToolShed.ListPlus(--- * Types--- ** Type-synonyms-	ChunkLength,---	Split,--- * Functions-	chunk,-	excise,-	groupComparing,-	linearise,-	merge,-	mergeBy,---	splitsFrom,-	splitsLeftFrom,-	splitsRightFrom,-	takeUntil-) where--import qualified	Control.Arrow-import qualified	Data.List---- | The length of the chunks into which a list is split.-type ChunkLength	= Int--{- |-	* Splits a list into length-@size@ pieces, where @(size >= 0)@.--	* The last chunk will be shorter, if @n@ isn't an aliquot part of the input list-length.--	* If @(size == 0)@, 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)@.--}-chunk ::-	ChunkLength-	-> [a]		-- ^ The polymorphic input list to be chunked.-	-> [[a]]-chunk size list-	| size < 0	= error $ "ToolShed.ListPlus.chunk:\tnegative chunk-size=" ++ show size-	| otherwise	= chunk' list-	where-		chunk' :: [a] -> [[a]]-		chunk' []	= []-		chunk' a	= uncurry (:) . Control.Arrow.second chunk' $ splitAt size a---- | Remove the single indexed element from the list.-excise ::-	Int	-- ^ The index.-	-> [a]	-- ^ The polymorphic input list.-	-> [a]	-- ^ The same list, with the indexed element removed.-excise 0	= tail	--Just for efficiency.-excise i	= uncurry (++) . Control.Arrow.second tail . splitAt i--{- |-	* Much like 'Data.List.GroupBy', but where the normal binary predicate,-	is composed from equality, after the same unary translation-function has been applied to both list-elements.--	* cf. 'GHC.Exts.groupWith', which uses the function parameter to both sort and group.--}-groupComparing :: Eq b-	=> (a -> b)	-- ^ Translates elements from the list, prior to testing the translated values for equality.-	-> [a]		-- ^ The polymorphic input list to group.-	-> [[a]]	-- ^ The same list split into chunks of the required length.-groupComparing f	= Data.List.groupBy (\a b -> f a == f b)---- | Converts a list of /Pairs/, into a narrower list.-linearise :: [(a, a)] -> [a]-linearise []			= []-linearise ((l, r) : remainder)	= l : r : linearise remainder	--Recurse--{- |-	* Merge two sorted lists, to product a single sorted list.--	* The merge-process is /stable/, in that where items from each list are equal, they remain in the original order.--}-merge :: Ord a => [a] -> [a] -> [a]-merge [] r		= r-merge l []		= l-merge l@(x : xs) r@(y : ys)-	| x > y		= y : merge l ys-	| otherwise	= x : merge xs r--{- |-	* Merge two sorted lists, according to the specified order, to product a single sorted list.--	* The merge-process is /stable/, in that where items from each list are equal, they remain in the original order.--}-mergeBy :: Ord a => (a -> a -> Ordering) -> [a] -> [a] -> [a]-mergeBy _ [] r		= r-mergeBy _ l []		= l-mergeBy cmp l@(x : xs) r@(y : ys)-	| x `cmp` y == GT	= y : mergeBy cmp l ys-	| otherwise		= x : mergeBy cmp xs r ---- | The polymorphic pair, resulting from splitting a list of arbitrary type.-type Split a	= ([a] {-left list-}, [a] {-right list-})---- | Use the specified transformation, to generate a list of 'Split's, from the initial one.-splitsFrom ::-	(Split a -> Split a)	-- ^ The function used to transform one /split/ into the next.-	-> Int			-- ^ Index.-	-> [a]			-- ^ The polymorphic input list from which the /splits/ are generated.-	-> [Split a]		-- ^ The list of all required splits of the single input list.-splitsFrom transformation i	= iterate transformation . splitAt i--{- |-	* Create the set of all 'Split's, migrating left from the specified location.--	* CAVEAT: 'init' fails when 'fst' has been reduced to null.--}-splitsLeftFrom ::-	Int		-- ^ Index.-	-> [a]		-- ^ The polymorphic input list from which the /splits/ are generated, as the index is stepped left-	-> [Split a]	-- ^ The list of all required splits of the single input list.-splitsLeftFrom start-	| start < 0	= error $ "ToolShed.ListPlus.splitsLeftFrom:\tnegative starting-index; " ++ show start-	| otherwise	= splitsFrom (\(l, r) -> (init l, last l : r)) start--{- |-	* Create the set of all 'Split's, migrating right from the specified location.--	* CAVEAT: pattern-match against @ : @ fails, when 'snd' has been reduced to null.--}-splitsRightFrom ::-	Int		-- ^ Index.-	-> [a]		-- ^ The polymorphic input list from which the /splits/ are generated, as the index is stepped right.-	-> [Split a]	-- ^ The list of all required splits of the single input list.-splitsRightFrom start-	| start < 0	= error $ "ToolShed.ListPlus.splitsRightFrom:\tnegative starting-index; " ++ show start-	| otherwise	= splitsFrom (\(l, r : rs) -> (l ++ [r], rs)) start--{- |-	* Take until the specified predicate is satisfied; /including/ the item which satisfied it.--	* NB: @takeWhile (not . test)@ would return one fewer item.--}-takeUntil ::-	(a -> Bool)	-- ^ Predicate, used to determine the last item taken.-	-> [a]		-- ^ The polymorphic input list.-	-> [a]-takeUntil predicate	= takeUntil'	where-	takeUntil' (x : xs)	= x {-take regardless-} : if predicate x-		then []-		else takeUntil' xs-	takeUntil' _		= []-
src/ToolShed/Options.hs view
@@ -25,8 +25,8 @@ 	Options(..) ) where -import ToolShed.Defaultable	as Defaultable+import qualified	ToolShed.Defaultable  -- | Similar to the class 'Text.Regex.Base.RegexLike.RegexOptions'.-class Defaultable a => Options a	where+class ToolShed.Defaultable.Defaultable a => Options a	where 	blankValue	:: a	-- ^ The /undefined/ state of the data-type, which may be literal, but could alternatively be a logical starting value.
− src/ToolShed/Pair.hs
@@ -1,44 +0,0 @@-{--	Copyright (C) 2010 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 Pairs.--}--module ToolShed.Pair(--- * Functions-	mirror,--- ** Predicates-	both,-	neither-) where--import	Control.Arrow((***))---- | Apply the same transformation to both halves of a /Pair/.-mirror :: (a -> b) -> (a, a) -> (b, b)-mirror f	= f *** f---- | 'True' if both halves of the /Pair/ are.-both :: (Bool, Bool) -> Bool-both	= uncurry (&&)---- | 'True' if neither half of the /Pair/ is.-neither :: (Bool, Bool) -> Bool-neither	= not . uncurry (||)-
src/ToolShed/SelfValidate.hs view
@@ -22,13 +22,51 @@  module ToolShed.SelfValidate( -- * Type-classes-	SelfValidator(..)+	SelfValidator(..),+-- ** Functions+	getFirstError,+	extractErrors ) where +import qualified	Data.Array.IArray+import qualified	Data.Map+import qualified	Data.Set+ -- | The interface to which data which can self-validate should conform.-class SelfValidator a	where-	isValid	:: a -> Bool	-- ^ The data which implements this interface should return 'True' if internally consistent.+class SelfValidator v	where+	getErrors	:: v -> [String]	-- ^ Return either null, or the reasons why the data is invalid. -instance SelfValidator a => SelfValidator [a]	where-	isValid	= all isValid	--NB: a null list is presumed to be OK.+	isValid		:: v -> Bool		-- ^ The data which implements this interface should return 'True' if internally consistent.+	isValid	= null . getErrors	--Default implementation.++instance (SelfValidator v) => SelfValidator (Maybe v)	where+	getErrors (Just v)	= getErrors v+	getErrors _		= []++instance (SelfValidator a, SelfValidator b) => SelfValidator (a, b)	where+	getErrors (a, b)	= getErrors a ++ getErrors b++instance SelfValidator v => SelfValidator [v]	where+	getErrors	= concatMap getErrors++instance SelfValidator v => SelfValidator (Data.Set.Set v)	where+	getErrors	= Data.Set.fold ((++) . getErrors) []++instance SelfValidator v => SelfValidator (Data.Map.Map k v)	where+	getErrors	= Data.Map.fold ((++) . getErrors) []++instance (Data.Array.IArray.Ix index, SelfValidator element) => SelfValidator (Data.Array.IArray.Array index element)	where+	getErrors	= concatMap getErrors . Data.Array.IArray.elems++-- | Returns the first error only (so only call on failure of 'isValid'), since subsequent tests may be based on invalid data.+getFirstError :: SelfValidator v => v -> String+getFirstError selfValidator+	| null errors	= error "ToolShed.SelfValidate.getFirstError:\tzero errors ?!"+	| otherwise	= head errors+	where+		errors	= getErrors selfValidator++-- | Filters failed tests amongst those specified.+extractErrors :: [(Bool, String)] -> [String]+extractErrors	= map snd . filter fst 
+ src/ToolShed/System/File.hs view
@@ -0,0 +1,96 @@++{-+	Copyright (C) 2011 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@]	File-operations.+-}++module ToolShed.System.File(+-- * Types+-- ** Type-synonyms+	SearchPath,+	LocatedData,+-- * Functions+	locate,+	getFile,+	fromFile,+-- ** Accessors+	getFilePath,+	getData+) where++import			Control.Applicative((<$>))+import qualified	Control.Exception+import qualified	Control.Monad+import qualified	Data.List+import qualified	System.Directory+import qualified	System.FilePath+import			System.FilePath((</>))+import qualified	System.IO.Error++-- | The ordered sequence of directories, searched for a file.+type SearchPath	= [System.FilePath.FilePath]++{- |+	* Locates all instances of the specified file, on the /search-path/.++	* CAVEAT: invalid or duplicate paths are silently removed.++	* CAVEAT: doesn't perform file-globbing.+-}+locate :: System.FilePath.FilePath -> SearchPath -> IO [System.FilePath.FilePath]+locate fileName	= Control.Monad.filterM System.Directory.doesFileExist . filter System.FilePath.isValid . Data.List.nubBy System.FilePath.equalFilePath . map (System.FilePath.normalise . (</> fileName))++-- | A file-path, and the contents read from it.+type LocatedData a	= (System.FilePath.FilePath, a)++-- | Accessor.+getFilePath :: LocatedData a -> System.FilePath.FilePath+getFilePath	= fst++-- | Accessor.+getData :: LocatedData a -> a+getData	= snd++{- |+	Traverse the /search-path/, looking for matching instances of the specified file-name,+	and either throw an exception, or return a pair composed from the path to the first matching file, together with its contents.+-}+getFile :: System.FilePath.FilePath -> SearchPath -> IO (LocatedData String)+getFile fileName directories	= do+	filePaths	<- locate fileName directories++	if null filePaths+		then Control.Exception.throw . System.IO.Error.mkIOError System.IO.Error.doesNotExistErrorType ("Can't find in " ++ show directories) Nothing $ Just fileName+		else {-located-} let+			filePath	= head filePaths	--Discard any subsequent paths.+		in (,) filePath <$> readFile filePath++{- |+	* Returns the polymorphic data, read from the first matching file on the /search-path/, along with the path from which it was read.++	* Returns an error on failure to parse the contents of the first matching file found on the /search-path/.+-}+fromFile :: Read a => System.FilePath.FilePath -> SearchPath -> IO (LocatedData a)+fromFile fileName directories	= do+	(filePath, fileContents)	<- getFile fileName directories++	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='" ++ filePath ++ "'"
+ src/ToolShed/System/Random.hs view
@@ -0,0 +1,78 @@++{-+	Copyright (C) 2011 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@]	Utilities related to random-numbers.+-}++module ToolShed.System.Random(+-- * Functions+	randomGens,+	shuffle,+	generateSelection,+	generateSelectionFromBounded,+	select+) where++import qualified	Control.Arrow+import qualified	Data.List+import qualified	Data.Ord+import qualified	System.Random++-- | Constructs an infinite list of independent random-generators.+randomGens :: System.Random.RandomGen randomGen => randomGen -> [randomGen]+randomGens	= uncurry (:) . Control.Arrow.second randomGens . System.Random.split++{- |+	* Shuffles the specified finite list.++	* 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.+-}+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])++{- |+	* Generate an infinite list of items, each 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 randomGen l	= map (l !!) $ System.Random.randomRs (0, pred $ length l) randomGen++-- | Return a random element from the specified list.+select :: System.Random.RandomGen randomGen => randomGen -> [a] -> a+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.++	* E.g. @ (generateSelectionFromBounded `fmap` System.Random.getStdGen) :: IO [Bool] @.+-}+generateSelectionFromBounded :: (System.Random.RandomGen randomGen, Bounded a, System.Random.Random a) => randomGen -> [a]+generateSelectionFromBounded	= System.Random.randomRs (minBound, maxBound)+
+ src/ToolShed/System/TimeAction.hs view
@@ -0,0 +1,49 @@+{-+	Copyright (C) 2011 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@]	Determines the CPU-time, required to evaluate the specified IO-action.++-}++module ToolShed.System.TimeAction(+-- * Functions+	getCPUSeconds,+	printCPUSeconds+) where++import qualified	System.CPUTime+import qualified	System.IO++-- | Time the specified IO-action, returning the required number of CPU-seconds and the result, as a 'Pair'.+getCPUSeconds :: Fractional seconds => IO result -> IO (seconds, result)+getCPUSeconds action	= do+	startTime	<- System.CPUTime.getCPUTime+	result		<- action+	endTime		<- System.CPUTime.getCPUTime++	return (fromInteger (endTime - startTime) / 1e12 {-convert from pico-seconds-}, result)++-- | Print the time required by the specified IO-action.+printCPUSeconds :: IO result -> IO result+printCPUSeconds action	= do+	(cpuSeconds, result)	<- getCPUSeconds action++	System.IO.hPutStrLn System.IO.stderr $ "CPU-seconds:\t" ++ show (cpuSeconds :: Double)++	return {-to IO-monad-} result
+ src/ToolShed/System/TimePure.hs view
@@ -0,0 +1,78 @@+{-# LANGUAGE CPP #-}+{-+	Copyright (C) 2010 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@]	Determines the CPU-time, required to evaluate the specified pure expression.++-}++module ToolShed.System.TimePure(+-- * Functions+	getCPUSeconds,+	printCPUSeconds+) where++import qualified	System.CPUTime+import qualified	System.IO++{-+	The function used to force evaluation of the pure expression 'rnf',+	and the type-class which the polymorphic data must implement 'NFData',+	has been relocated from module "Control.Parallel.Strategies" to "Control.DeepSeq".+-}+#ifdef HAVE_DEEPSEQ+import			Control.DeepSeq(NFData, deepseq)+#else+import			Control.Parallel(pseq)+import			Control.Parallel.Strategies(NFData, rnf)+#endif++{- |+	* Time the specified pure expression, returning the required number of CPU-seconds and the result, as a 'Pair'.++	* CAVEAT: as a side-effect, the expression is /deep/ evaluated.+-}+getCPUSeconds :: (Fractional seconds, NFData expression)+	=> expression			-- ^ Arbitrary polymorphic expression.+	-> IO (seconds, expression)	-- ^ The original expression, tagged with the CPU-seconds taken.+getCPUSeconds expression	= do+	start	<- System.CPUTime.getCPUTime+	end	<-+#ifdef HAVE_DEEPSEQ+		expression `deepseq`+#else+		rnf expression `pseq`+#endif+			System.CPUTime.getCPUTime++	return {-to IO-monad-} (fromInteger (end - start) / 1e12 {-convert from pico-seconds-}, expression)++{- |+	* Print the time required by the specified pure expression.++	* CAVEAT: as a side-effect, the expression is /deep/ evaluated.+-}+printCPUSeconds :: NFData expression => expression -> IO expression+printCPUSeconds expression	= do+	(cpuSeconds, result)	<- getCPUSeconds expression++	System.IO.hPutStrLn System.IO.stderr $ "CPU-seconds:\t" ++ show (cpuSeconds :: Double)++	return {-to IO-monad-} result+
+ src/ToolShed/Test/Data/List.hs view
@@ -0,0 +1,69 @@+{-+	Copyright (C) 2012 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.List".+-}++module ToolShed.Test.Data.List(+-- * Functions+	quickChecks+) where++import qualified	Data.List+import qualified	Data.Ord+import qualified	Data.Set+import qualified	ToolShed.Data.List+import qualified	Test.QuickCheck+import			Test.QuickCheck((==>))++-- | Defines invariant properties.+quickChecks :: IO ()+quickChecks =+	Test.QuickCheck.quickCheck prop_chunk+	>> Test.QuickCheck.quickCheck `mapM_` [prop_findConvergence, prop_gatherSet]+	>> Test.QuickCheck.quickCheck prop_gatherBy+	>> Test.QuickCheck.quickCheck prop_permutations+	>> Test.QuickCheck.quickCheck prop_linearise+	>> Test.QuickCheck.quickCheck prop_merge+	where+		prop_chunk :: Int -> [Int] -> Test.QuickCheck.Property+		prop_chunk i l		= Test.QuickCheck.label "prop_chunk" $ concat (ToolShed.Data.List.chunk (succ $ abs i) l) == l++		prop_findConvergence, prop_gatherSet :: Int -> Test.QuickCheck.Property+		prop_findConvergence	= Test.QuickCheck.label "prop_findConvergence" . (== 0) . ToolShed.Data.List.findConvergence . iterate (fst . (`quotRem` 2))+		prop_gatherSet n	= Test.QuickCheck.label "prop_gatherSet" . (== l) . concat . ToolShed.Data.List.gather $ Data.Set.fromDistinctAscList l	where+			l	= [0 .. n `mod` 1024]++		prop_gatherBy :: [Int] -> Test.QuickCheck.Property+		prop_gatherBy l	= Test.QuickCheck.label "prop_gatherBy" $ map Data.List.sort (+			ToolShed.Data.List.gatherBy even l+		 ) == (+			map Data.List.sort . Data.List.groupBy (ToolShed.Data.List.equalityBy even) $ Data.List.sortBy (Data.Ord.comparing even) l+		 )++		prop_permutations :: [[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_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++		prop_merge :: [Int] -> [Int] -> Test.QuickCheck.Property+		prop_merge x y	= Test.QuickCheck.label "prop_merge" $ ToolShed.Data.List.merge (Data.List.sort x) (Data.List.sort y) == Data.List.sort (x ++ y)+
+ src/ToolShed/Test/Data/List/Runlength.hs view
@@ -0,0 +1,36 @@+{-+	Copyright (C) 2012 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.List.Runlength".+-}++module ToolShed.Test.Data.List.Runlength(+-- * Functions+	quickChecks+) where++import qualified	ToolShed.Data.List.Runlength+import qualified	Test.QuickCheck++-- | Defines invariant properties.+quickChecks :: IO ()+quickChecks	= Test.QuickCheck.quickCheck prop_runLength where+	prop_runLength :: [Int] -> Test.QuickCheck.Property+	prop_runLength l	= Test.QuickCheck.label "prop_runLength" $ ToolShed.Data.List.Runlength.decode (ToolShed.Data.List.Runlength.encode l) == l+
+ src/ToolShed/Test/Data/List/Splits.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE CPP #-}+{-+	Copyright (C) 2012 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.List.Splits".+-}++module ToolShed.Test.Data.List.Splits(+-- * Functions+	quickChecks+) where++import			Control.Arrow((***))+import qualified	Data.List+import qualified	Data.Ord+import qualified	Data.Set+import qualified	ToolShed.Data.List.Splits+import qualified	Test.QuickCheck+import			Test.QuickCheck((==>))++#if MIN_VERSION_base(4,3,0)+import	Data.Tuple(swap)+#else+-- | Swap the components of a pair.+swap :: (a, b) -> (b, a)+swap (a, b)	= (b, a)+#endif++-- | Defines invariant properties.+quickChecks :: IO ()+quickChecks =	Test.QuickCheck.quickCheck prop_splitsFrom where+	prop_splitsFrom :: Int -> [Int] -> Test.QuickCheck.Property+	prop_splitsFrom i l	= not (null l) ==> Test.QuickCheck.label "prop_splitsFrom" $ take n (ToolShed.Data.List.Splits.splitsLeftFrom index l) == take n (map (swap . (reverse *** reverse)) . ToolShed.Data.List.Splits.splitsRightFrom (length l - index) $ reverse l)	where+		index	= i `mod` length l+		n	= succ index
+ src/ToolShed/Test/QuickChecks.hs view
@@ -0,0 +1,37 @@+{-+	Copyright (C) 2012 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@]	Calls the /quickChecks/-functions for modules supporting this feature.+-}++module ToolShed.Test.QuickChecks(+-- * Functions+	run+) where++import qualified	ToolShed.Test.Data.List+import qualified	ToolShed.Test.Data.List.Runlength+import qualified	ToolShed.Test.Data.List.Splits++-- | Run the /quickChecks/-functions for modules supporting this feature.+run :: IO ()+run	= 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+
− src/ToolShed/TimeAction.hs
@@ -1,49 +0,0 @@-{--	Copyright (C) 2011 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@]	Determines the CPU-time, required to evaluate the specified IO-action.---}--module ToolShed.TimeAction(--- * Functions-	getCPUSeconds,-	printCPUSeconds-) where--import qualified	System.CPUTime-import qualified	System.IO---- | Time the specified IO-action, returning the seconds and result as a 'Pair'.-getCPUSeconds :: Fractional seconds => IO result -> IO (seconds, result)-getCPUSeconds action	= do-	startTime	<- System.CPUTime.getCPUTime-	result		<- action-	endTime		<- System.CPUTime.getCPUTime--	return (fromInteger (endTime - startTime) / 1e12 {-convert from pico-seconds-}, result)---- | Print the time required by the specified IO-action.-printCPUSeconds :: IO result -> IO result-printCPUSeconds action	= do-	(cpuSeconds, result)	<- getCPUSeconds action--	System.IO.hPutStrLn System.IO.stderr $ "CPU-seconds:\t" ++ show (cpuSeconds :: Double)--	return {-to IO-monad-} result
− src/ToolShed/TimePure.hs
@@ -1,78 +0,0 @@-{-# LANGUAGE CPP #-}-{--	Copyright (C) 2010 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@]	Determines the CPU-time, required to evaluate the specified pure expression.---}--module ToolShed.TimePure (--- * Functions-	getCPUSeconds,-	printCPUSeconds-) where--import qualified	System.CPUTime-import qualified	System.IO--{--	The function used to force evaluation of the pure expression 'rnf',-	and the type-class which the polymorphic data must implement 'NFData',-	has been relocated from module "Control.Parallel.Strategies" to "Control.DeepSeq".--}-#ifdef HAVE_DEEPSEQ-import			Control.DeepSeq(NFData, deepseq)-#else-import			Control.Parallel(pseq)-import			Control.Parallel.Strategies(NFData, rnf)-#endif--{- |-	* Time the specified pure expression, returning the seconds and result as a 'Pair'.--	* CAVEAT: as a side-effect, the expression is /deep/ evaluated.--}-getCPUSeconds :: (Fractional seconds, NFData expression)-	=> expression			-- ^ Arbitrary polymorphic expression.-	-> IO (seconds, expression)	-- ^ The original expression, tagged with the CPU-seconds taken.-getCPUSeconds expression	= do-	start	<- System.CPUTime.getCPUTime-	end	<--#ifdef HAVE_DEEPSEQ-		expression `deepseq`-#else-		rnf expression `pseq`-#endif-			System.CPUTime.getCPUTime--	return {-to IO-monad-} (fromInteger (end - start) / 1e12 {-convert from pico-seconds-}, expression)--{- |-	* Print the time required by the specified pure expression.--	* CAVEAT: as a side-effect, the expression is /deep/ evaluated.--}-printCPUSeconds :: NFData expression => expression -> IO expression-printCPUSeconds expression	= do-	(cpuSeconds, result)	<- getCPUSeconds expression--	System.IO.hPutStrLn System.IO.stderr $ "CPU-seconds:\t" ++ show (cpuSeconds :: Double)--	return {-to IO-monad-} result-
− src/ToolShed/Unsafe.hs
@@ -1,56 +0,0 @@-{--	Copyright (C) 2010 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@]--	* Provides impure functions to print & return the specified value.--	* The pure interfaces permit calls from outside the /IO-monad/.-- [@TODO@]	Review function-names.--}--module ToolShed.Unsafe(--- * Functions-	print',-	printShow-) where--import qualified	System.IO-import qualified	System.IO.Unsafe--{-# NOINLINE print' #-}--- | A transparent print-function, for use in debugging.-print' :: Show s-	=> s	-- ^ Arbitrary polymorphic input-data.-	-> s	-- ^ Output (identical to input).-print'	= System.IO.Unsafe.unsafePerformIO . f	where-	f :: Show s => s -> IO s-	f x	= System.IO.hPrint System.IO.stderr x	>> return {-to IO-monad-} x--{-# NOINLINE printShow #-}--- | A transparent print-function, which prepends the specified label, for use in debugging.-printShow :: Show s-	=> String	-- ^ The label to be printed before the value of the input data.-	-> s		-- ^ Arbitrary polymorphic input-data.-	-> s		-- ^ Output (identical to input).-printShow label	= System.IO.Unsafe.unsafePerformIO . f label	where-	f :: Show s => String -> s -> IO s-	f s x	= System.IO.hPutStrLn System.IO.stderr (s ++ show x)	>> return {-to IO-monad-} x-
toolshed.cabal view
@@ -1,6 +1,6 @@ --Package-properties Name:			toolshed-Version:		0.12.0.0+Version:		0.13.0.0 Cabal-Version:		>= 1.6 Copyright:		(C) 2010 Dr. Alistair Ward License:		GPL@@ -30,24 +30,56 @@     hs-source-dirs:	src      Exposed-modules:+        ToolShed.Arbitrary.Array+        ToolShed.Arbitrary.ArrayElem+        ToolShed.Arbitrary.Map+        ToolShed.Arbitrary.Set+        ToolShed.Data.List+        ToolShed.Data.List.Runlength+        ToolShed.Data.List.Splits+        ToolShed.Data.Pair         ToolShed.Defaultable-        ToolShed.ListPlus         ToolShed.Options-        ToolShed.Pair         ToolShed.SelfValidate-        ToolShed.TimeAction-        ToolShed.TimePure-        ToolShed.Unsafe +        ToolShed.System.File+        ToolShed.System.Random+        ToolShed.System.TimeAction+        ToolShed.System.TimePure -    Build-depends:	base == 4.*+    Build-depends:+        array,+        base == 4.*,+        containers,+        directory,+        filepath,+        QuickCheck >= 2.2,+        random      GHC-options:	-Wall -O2-    GHC-prof-options:	-prof -auto-all -caf-all +    if impl(ghc >= 7.4.1)+        GHC-prof-options:	-prof -fprof-auto -fprof-cafs+    else+        GHC-prof-options:	-prof -auto-all -caf-all+     if flag(haveDeepSeq)         Build-depends:	deepseq >= 1.1         CPP-options:	-DHAVE_DEEPSEQ      if impl(ghc >= 7.0) && flag(llvm)         GHC-options:	-fllvm++Executable toolshed+    hs-source-dirs:	src++    Main-Is:		Main.hs++    Other-modules:+        ToolShed.Test.QuickChecks+        ToolShed.Test.Data.List+        ToolShed.Test.Data.List.Runlength+        ToolShed.Test.Data.List.Splits++    Build-depends:+        Cabal >= 1.6 && < 2