diff --git a/changelog b/changelog
--- a/changelog
+++ b/changelog
@@ -4,33 +4,33 @@
 	* First version of the package.
 0.10.0.0
 	* Created "src/ToolShed/" sub-directory & then modified module-names accordingly.
-	* Removed the module "Pair", and relocated its only function to the sole caller in the package "Bridge".
+	* Removed the module "Pair", & relocated its only function to the sole caller in the package "Bridge".
 	* Added a makefile.
 	* Qualified identifiers used in error-messages.
 0.10.0.1
 	* Tested with ghc-7.0.1, & conditionally replaced use of the package 'parallel' with 'deepseq', in the module "TimePure".
 0.10.1.0
-	* Added 'ToolShed.Arithmetic.nCr', "ToolShed.Options" and "ToolShed.Package".
+	* Added 'ToolShed.Arithmetic.nCr', "ToolShed.Options" & "ToolShed.Package".
 0.10.2.0
 	* Renamed package from 'ToolShed' to 'toolshed', for compatibility with Debian's ".deb"-format.
 0.11.0.0
 	* Added manually controlled "llvm" flag to "toolshed.cabal".
 	* Removed the module "ToolShed.Package", for which 'Distribution.Package.PackageIdentifier' is a suitable alternative.
 	* Added 'NOINLINE' pragma to each function in module "Unsafe".
-	* Relocated 'mean' and 'nCr' from "ToolShed.Arithmetic", to the package "factory".
+	* Relocated 'mean' & 'nCr' from "ToolShed.Arithmetic", to the package "factory".
 	* Added function 'ListPlus.groupComparing'.
 	* Changed identifier for type-parameters, to better reflect its role.
-	* Relocated the remaining rather pointless functions from the module "ToolShed.Arithmetic" and deleted it.
-	* Added module "ToolShed.Defaultable", and derived class 'ToolShed.Options.Options' from it.
+	* Relocated the remaining rather pointless functions from the module "ToolShed.Arithmetic" & deleted it.
+	* Added module "ToolShed.Defaultable", & derived class 'ToolShed.Options.Options' from it.
 0.11.1.0
-	* Added functions 'merge' and 'mergeBy' to module "ToolShed.ListPlus" and exported a new type-synonym 'ToolShed.ListPlus.ChunkLength'.
+	* 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".
 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'.
+	* 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'.
 0.13.0.0
 	* Removed module "ToolShed.Unsafe".
 	* Renamed:
@@ -38,17 +38,30 @@
 		"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".
+	* Migrated 'ToolShed.Data.List.RunLengthCode' & associated functions, into a new module "ToolShed.Data.List.Runlength".
+	* Migrated 'ToolShed.Data.List.Splits' & 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 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 method 'ToolShed.SelfValidate.getErrors', and supporting functions 'ToolShed.SelfValidate.getFirstErrors' and 'ToolShed.SelfValidate.extractErrors'.
+	* Added method 'ToolShed.SelfValidate.getErrors', & supporting functions 'ToolShed.SelfValidate.getFirstErrors' & 'ToolShed.SelfValidate.extractErrors'.
 	* Create module "ToolShed.Arbitrary.*".
-	* Added "Main", "ToolShed.Test.QuickChecks" and "ToolShed.Test.Data.List" to facilitate testing.
+	* Added "Main", "ToolShed.Test.QuickChecks" & "ToolShed.Test.Data.List" to facilitate testing.
 	* Removed 'ToolShed.Data.Pair.both'.
-	* Replaced "System" with "System.Environment" and "System.Exit".
+	* Replaced "System" with "System.Environment" & "System.Exit".
 	* Removed dependency on "haskell98".
+0.14.0.0
+	* 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".
+	* 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'.
+	* Migrated functions 'gather', 'gatherBy', 'hasDuplicates' which merely operate on 'Data.Foldable.Foldable' types from module "ToolShed.Data.List", into new module "ToolShed.Data.Foldable".
+
diff --git a/makefile b/makefile
--- a/makefile
+++ b/makefile
@@ -19,37 +19,37 @@
 
 install: build haddock
 	@[ -z "$$CABAL_INSTALL_OPTIONS" ] || echo "INFO: CABAL_INSTALL_OPTIONS='$$CABAL_INSTALL_OPTIONS'"
-	runhaskell Setup.hs $@ $$CABAL_INSTALL_OPTIONS
+	runhaskell Setup $@ $$CABAL_INSTALL_OPTIONS
 
 prof:
 	CABAL_CONFIGURE_OPTIONS="--enable-library-profiling $$CABAL_CONFIGURE_OPTIONS" make install
 
 copy: build
 	@[ -z "$$CABAL_COPY_OPTIONS" ] || echo "INFO: CABAL_COPY_OPTIONS='$$CABAL_COPY_OPTIONS'"
-	runhaskell Setup.hs $@ $$CABAL_COPY_OPTIONS
+	runhaskell Setup $@ $$CABAL_COPY_OPTIONS
 
 build: configure
 	@[ -z "$$CABAL_BUILD_OPTIONS" ] || echo "INFO: CABAL_BUILD_OPTIONS='$$CABAL_BUILD_OPTIONS'"
-	runhaskell Setup.hs $@ $$CABAL_BUILD_OPTIONS
+	runhaskell Setup $@ $$CABAL_BUILD_OPTIONS
 
 configure: toolshed.cabal Setup.hs
 	@[ -z "$$CABAL_CONFIGURE_OPTIONS" ] || echo "INFO: CABAL_CONFIGURE_OPTIONS='$$CABAL_CONFIGURE_OPTIONS'"
-	runhaskell Setup.hs $@ $$CABAL_CONFIGURE_OPTIONS	#--user
+	runhaskell Setup $@ $$CABAL_CONFIGURE_OPTIONS	#--user
 
 haddock: configure
-	PATH=~/.cabal/bin:$$PATH runhaskell Setup.hs $@ --hyperlink-source	#Amend path to find 'HsColour', as required for 'hyperlink-source'.
+	PATH=~/.cabal/bin:$$PATH runhaskell Setup $@ --hyperlink-source	#Amend path to find 'HsColour', as required for 'hyperlink-source'.
 
 hlint:
 	@$@ src/
 
-sdist: configure
-	runhaskell Setup.hs $@
+sdist:
+	runhaskell Setup $@
 
 check: sdist
 	cabal upload --check --verbose=3 dist/*.tar.gz;
 
 clean:
-	runhaskell Setup.hs $@
+	runhaskell Setup $@
 	find src -type f \( -name '*.hc' -o -name '*.hcr' -o -name '*.hi' -o -name '*.o' \) -delete
 
 help:
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -53,33 +53,37 @@
 main :: IO ()
 main	= do
 	progName	<- System.Environment.getProgName
-	args		<- System.Environment.getArgs
 
 	let
-		usage :: String
-		usage	= "Usage:\t" ++ G.usageInfo progName optDescrList
+		usageMessage :: String
+		usageMessage	= "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."
+--				 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
+			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
 				packageIdentifier :: Distribution.Package.PackageIdentifier
 				packageIdentifier	= Distribution.Package.PackageIdentifier {
-					Distribution.Package.pkgName	= Distribution.Package.PackageName "toolshed",
+					Distribution.Package.pkgName	= Distribution.Package.PackageName progName,	--CAVEAT: coincidentally.
 					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
+				author :: String
+				author	= "Dr. Alistair Ward"
 
+			printUsage	= System.IO.hPutStrLn System.IO.stderr usageMessage	>> System.Exit.exitWith System.Exit.ExitSuccess
+			runQuickChecks	= ToolShed.Test.QuickChecks.run				>> System.Exit.exitWith System.Exit.ExitSuccess
+
+	args	<- System.Environment.getArgs
+
 --	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.
+		(_, _, errors)			-> System.IO.Error.ioError . System.IO.Error.userError $ concat errors ++ usageMessage	--Throw.
 
diff --git a/src/ToolShed/Arbitrary/Array.hs b/src/ToolShed/Arbitrary/Array.hs
deleted file mode 100644
--- a/src/ToolShed/Arbitrary/Array.hs
+++ /dev/null
@@ -1,52 +0,0 @@
-{-# 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
-
diff --git a/src/ToolShed/Arbitrary/ArrayElem.hs b/src/ToolShed/Arbitrary/ArrayElem.hs
deleted file mode 100644
--- a/src/ToolShed/Arbitrary/ArrayElem.hs
+++ /dev/null
@@ -1,43 +0,0 @@
-{-# 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
-
diff --git a/src/ToolShed/Arbitrary/Map.hs b/src/ToolShed/Arbitrary/Map.hs
deleted file mode 100644
--- a/src/ToolShed/Arbitrary/Map.hs
+++ /dev/null
@@ -1,39 +0,0 @@
-{-# 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
-
diff --git a/src/ToolShed/Arbitrary/Set.hs b/src/ToolShed/Arbitrary/Set.hs
deleted file mode 100644
--- a/src/ToolShed/Arbitrary/Set.hs
+++ /dev/null
@@ -1,39 +0,0 @@
-{-# 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
-
diff --git a/src/ToolShed/Data/Foldable.hs b/src/ToolShed/Data/Foldable.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Data/Foldable.hs
@@ -0,0 +1,49 @@
+{-
+	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@]	Miscellaneous polymorphic operations on 'Data.Foldable.Foldable' types.
+-}
+
+module ToolShed.Data.Foldable(
+-- * Functions
+	gather,
+	gatherBy,
+-- ** Predicates
+	hasDuplicates
+) where
+
+import			Control.Arrow((&&&))
+import qualified	Data.Foldable
+import qualified	Data.Map
+
+{- |
+	* Group equal (though not necessarily adjacent; c.f. 'Data.List.groupBy') 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 (uncurry (Data.Map.insertWith (++)) . (f &&& return {-to List-monad-})) Data.Map.empty
+
+-- | A specific instance of 'gatherBy'.
+gather :: (Data.Foldable.Foldable f, Ord a) => f a -> [[a]]
+gather	= gatherBy id
+
+-- | Whether the specified collection contains any equal items.
+hasDuplicates :: (Data.Foldable.Foldable f, Ord a) => f a -> Bool
+hasDuplicates	= any ((> 1) . length) . gather
diff --git a/src/ToolShed/Data/List.hs b/src/ToolShed/Data/List.hs
--- a/src/ToolShed/Data/List.hs
+++ b/src/ToolShed/Data/List.hs
@@ -30,23 +30,22 @@
 	equalityBy,
 	findConvergence,
 	findConvergenceBy,
-	gather,
-	gatherBy,
 	linearise,
 	merge,
 	mergeBy,
+	nub',
+--	nubWithInt,
 	permutations,
 	takeUntil,
 	showListWith,
---	showListWithChar
+--	showListWithChar,
 --	showListWithString
 ) where
 
 import qualified	Control.Arrow
-import qualified	Data.Foldable
+import qualified	Data.IntSet
 import qualified	Data.List
-import qualified	Data.Map
---import qualified	Data.Ord
+import qualified	Data.Set
 
 -- | The length of the chunks into which a list is split.
 type ChunkLength	= Int
@@ -92,17 +91,20 @@
 findConvergence :: Eq a => [a] -> a
 findConvergence	= findConvergenceBy (==)
 
+{-# NOINLINE nub' #-}
+{-# RULES "nub'/Int" nub' = nubWithInt #-}
+
 {- |
-	* Group equal (though not necessarily adjacent) elements, according to the specified comparator.
+	* A version of 'Data.List.nub' with better time-complexity.
 
-	* The groups are returned in ascending order, whilst their elements remain in their original order.
+	* CAVEAT: it sorts the output as a side-effect, & consequently it requires a type which implements 'Ord'.
 -}
-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
+nub' :: Ord a => [a] -> [a]
+nub'	= Data.Set.toList . Data.Set.fromList
 
--- | A specific instance of 'gatherBy'.
-gather :: (Data.Foldable.Foldable f, Ord a) => f a -> [[a]]
-gather	= gatherBy id
+-- | A specialisation for type 'Int'.
+nubWithInt :: [Int] -> [Int]
+nubWithInt	= Data.IntSet.toList . Data.IntSet.fromList
 
 -- | Converts a list of /Pairs/, into a narrower list.
 linearise :: [(a, a)] -> [a]
diff --git a/src/ToolShed/SelfValidate.hs b/src/ToolShed/SelfValidate.hs
--- a/src/ToolShed/SelfValidate.hs
+++ b/src/ToolShed/SelfValidate.hs
@@ -44,16 +44,19 @@
 	getErrors _		= []
 
 instance (SelfValidator a, SelfValidator b) => SelfValidator (a, b)	where
-	getErrors (a, b)	= getErrors a ++ getErrors b
+	getErrors (x, y)	= getErrors x ++ getErrors y
 
+instance (SelfValidator a, SelfValidator b, SelfValidator c) => SelfValidator (a, b, c)	where
+	getErrors (x, y, z)	= getErrors x ++ getErrors y ++ getErrors z
+
 instance SelfValidator v => SelfValidator [v]	where
 	getErrors	= concatMap getErrors
 
 instance SelfValidator v => SelfValidator (Data.Set.Set v)	where
-	getErrors	= Data.Set.fold ((++) . getErrors) []
+	getErrors	= Data.Set.foldr ((++) . getErrors) []
 
 instance SelfValidator v => SelfValidator (Data.Map.Map k v)	where
-	getErrors	= Data.Map.fold ((++) . getErrors) []
+	getErrors	= Data.Map.foldr ((++) . getErrors) []
 
 instance (Data.Array.IArray.Ix index, SelfValidator element) => SelfValidator (Data.Array.IArray.Array index element)	where
 	getErrors	= concatMap getErrors . Data.Array.IArray.elems
diff --git a/src/ToolShed/System/File.hs b/src/ToolShed/System/File.hs
--- a/src/ToolShed/System/File.hs
+++ b/src/ToolShed/System/File.hs
@@ -48,15 +48,25 @@
 type SearchPath	= [System.FilePath.FilePath]
 
 {- |
-	* Locates all instances of the specified file, on the /search-path/.
+	* When supplied with an /absolute/ file-path, the /search-path/ is ignored and an exception is thrown if either the file-path is invalid or the file doesn't exist.
 
-	* CAVEAT: invalid or duplicate paths are silently removed.
+	* If the specified file-name is /relative/, all matching instances on the specified /search-path/ are returned.
 
 	* 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))
+locate fileName searchPath
+	| System.FilePath.isRelative fileName'		= Control.Monad.filterM System.Directory.doesFileExist . filter System.FilePath.isValid . Data.List.nubBy System.FilePath.equalFilePath $ map (System.FilePath.normalise . (</> fileName')) searchPath
+	| not $ System.FilePath.isValid fileName'	= Control.Exception.throw . System.IO.Error.userError $ "Invalid filename; " ++ fileName'
+	| otherwise					= do
+		fileExists	<- System.Directory.doesFileExist fileName'
 
+		if not fileExists
+			then Control.Exception.throw . System.IO.Error.mkIOError System.IO.Error.doesNotExistErrorType "No such file" Nothing $ Just fileName'
+			else return {-to IO-monad-} [fileName']
+	where
+		fileName'	= System.FilePath.normalise fileName
+
 -- | A file-path, and the contents read from it.
 type LocatedData a	= (System.FilePath.FilePath, a)
 
@@ -93,4 +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='" ++ filePath ++ "'"
+		_		-> error $ "ToolShed.System.File.fromFile:\tfailed to parse file=" ++ show filePath
+
diff --git a/src/ToolShed/System/Random.hs b/src/ToolShed/System/Random.hs
--- a/src/ToolShed/System/Random.hs
+++ b/src/ToolShed/System/Random.hs
@@ -37,7 +37,7 @@
 
 -- | Constructs an infinite list of independent random-generators.
 randomGens :: System.Random.RandomGen randomGen => randomGen -> [randomGen]
-randomGens	= uncurry (:) . Control.Arrow.second randomGens . System.Random.split
+randomGens	= uncurry (:) . Control.Arrow.second randomGens {-recurse-} . System.Random.split
 
 {- |
 	* Shuffles the specified finite list.
@@ -64,10 +64,11 @@
 
 -- | Return a random element from the specified list.
 select :: System.Random.RandomGen randomGen => randomGen -> [a] -> a
-select randomGen	= head . generateSelection randomGen
+select _ []		= error "ToolShed.System.Random.generateSelection:\tnull list"
+select randomGen l	= head $ generateSelection randomGen l
 
 {- |
-	* Generate an infinite list of items, each randomly selected, from the specified finite list of bounded items.
+	* 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.
 
diff --git a/src/ToolShed/System/TimeAction.hs b/src/ToolShed/System/TimeAction.hs
--- a/src/ToolShed/System/TimeAction.hs
+++ b/src/ToolShed/System/TimeAction.hs
@@ -37,7 +37,7 @@
 	result		<- action
 	endTime		<- System.CPUTime.getCPUTime
 
-	return (fromInteger (endTime - startTime) / 1e12 {-convert from pico-seconds-}, result)
+	return {-to IO-monad-} (fromInteger (endTime - startTime) / 1e12 {-convert from pico-seconds-}, result)
 
 -- | Print the time required by the specified IO-action.
 printCPUSeconds :: IO result -> IO result
diff --git a/src/ToolShed/Test/Data/Foldable.hs b/src/ToolShed/Test/Data/Foldable.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Test/Data/Foldable.hs
@@ -0,0 +1,49 @@
+{-
+	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.Foldable".
+-}
+
+module ToolShed.Test.Data.Foldable(
+-- * Functions
+	quickChecks
+) where
+
+import qualified	Data.List
+import qualified	Data.Ord
+import qualified	Data.Set
+import qualified	ToolShed.Data.Foldable
+import qualified	ToolShed.Data.List
+import qualified	Test.QuickCheck
+import			Test.QuickCheck((==>))
+
+-- | Defines invariant properties.
+quickChecks :: IO ()
+quickChecks = Test.QuickCheck.quickCheck prop_gatherSet >> Test.QuickCheck.quickCheck prop_gatherBy	where
+	prop_gatherSet :: Int -> Test.QuickCheck.Property
+	prop_gatherSet n	= Test.QuickCheck.label "prop_gatherSet" . (== l) . concat . ToolShed.Data.Foldable.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.Foldable.gatherBy even l
+	 ) == (
+		map Data.List.sort . Data.List.groupBy (ToolShed.Data.List.equalityBy even) $ Data.List.sortBy (Data.Ord.comparing even) l
+	 )
+
diff --git a/src/ToolShed/Test/Data/List.hs b/src/ToolShed/Test/Data/List.hs
--- a/src/ToolShed/Test/Data/List.hs
+++ b/src/ToolShed/Test/Data/List.hs
@@ -36,8 +36,8 @@
 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_findConvergence
+	>> Test.QuickCheck.quickCheck prop_nub
 	>> Test.QuickCheck.quickCheck prop_permutations
 	>> Test.QuickCheck.quickCheck prop_linearise
 	>> Test.QuickCheck.quickCheck prop_merge
@@ -45,17 +45,11 @@
 		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 :: 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_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 l	= not (null l')	==> Test.QuickCheck.label "prop_permutations" $ length (ToolShed.Data.List.permutations l') == product (map length l')	where
diff --git a/src/ToolShed/Test/Data/List/Splits.hs b/src/ToolShed/Test/Data/List/Splits.hs
--- a/src/ToolShed/Test/Data/List/Splits.hs
+++ b/src/ToolShed/Test/Data/List/Splits.hs
@@ -44,7 +44,7 @@
 
 -- | Defines invariant properties.
 quickChecks :: IO ()
-quickChecks =	Test.QuickCheck.quickCheck prop_splitsFrom where
+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
diff --git a/src/ToolShed/Test/QuickCheck/Arbitrary/Array.hs b/src/ToolShed/Test/QuickCheck/Arbitrary/Array.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Test/QuickCheck/Arbitrary/Array.hs
@@ -0,0 +1,59 @@
+{-# 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.Test.QuickCheck.Arbitrary.Array() where
+
+import			Control.Applicative((<$>))
+import qualified	Data.Array.IArray
+import qualified	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
+
+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	= 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
+
diff --git a/src/ToolShed/Test/QuickCheck/Arbitrary/ArrayElem.hs b/src/ToolShed/Test/QuickCheck/Arbitrary/ArrayElem.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Test/QuickCheck/Arbitrary/ArrayElem.hs
@@ -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.Test.QuickCheck.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
+
diff --git a/src/ToolShed/Test/QuickCheck/Arbitrary/Map.hs b/src/ToolShed/Test/QuickCheck/Arbitrary/Map.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Test/QuickCheck/Arbitrary/Map.hs
@@ -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.Test.QuickCheck.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
+
diff --git a/src/ToolShed/Test/QuickCheck/Arbitrary/Set.hs b/src/ToolShed/Test/QuickCheck/Arbitrary/Set.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Test/QuickCheck/Arbitrary/Set.hs
@@ -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.Test.QuickCheck.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
+
diff --git a/src/ToolShed/Test/QuickChecks.hs b/src/ToolShed/Test/QuickChecks.hs
--- a/src/ToolShed/Test/QuickChecks.hs
+++ b/src/ToolShed/Test/QuickChecks.hs
@@ -25,13 +25,17 @@
 	run
 ) where
 
+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
 
 -- | Run the /quickChecks/-functions for modules supporting this feature.
 run :: IO ()
-run	= putStrLn "Data.List"			>> ToolShed.Test.Data.List.quickChecks
+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
 
diff --git a/src/ToolShed/Test/ReversibleBoundedEnum.hs b/src/ToolShed/Test/ReversibleBoundedEnum.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Test/ReversibleBoundedEnum.hs
@@ -0,0 +1,34 @@
+{-
+	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@]	Facilities testing of custom implementations of 'Enum'.
+-}
+
+module ToolShed.Test.ReversibleBoundedEnum(
+-- * Functions
+-- ** Predicates
+	isReversible
+) where
+
+-- | Checks that composing 'pred' & 'succ' is equivalent to the identity.
+isReversible :: (Bounded r, Eq r, Enum r) => r -> Bool
+isReversible r
+	| r == minBound	= pred (succ r) == r
+	| otherwise	= succ (pred r) == r
+
diff --git a/src/ToolShed/Test/ReversibleEnum.hs b/src/ToolShed/Test/ReversibleEnum.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Test/ReversibleEnum.hs
@@ -0,0 +1,31 @@
+{-
+	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@]	Facilities testing of custom implementations of 'Enum'.
+-}
+
+module ToolShed.Test.ReversibleEnum(
+-- * Functions
+-- ** Predicates
+	isReversible
+) where
+
+-- | Checks that composing 'toEnum' & 'fromEnum' is equivalent to the identity.
+isReversible :: (Eq r, Enum r) => r -> Bool
+isReversible r	= toEnum (fromEnum r) == r
diff --git a/src/ToolShed/Test/ReversibleIO.hs b/src/ToolShed/Test/ReversibleIO.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Test/ReversibleIO.hs
@@ -0,0 +1,35 @@
+{-
+	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@]
+
+	* Facilities testing of custom implementations of 'Read' & 'Show'.
+
+	* CAVEAT: it doesn't actually do any IO.
+-}
+
+module ToolShed.Test.ReversibleIO(
+-- * Functions
+-- ** Predicates
+	isReversible
+) where
+
+-- | Checks that composing 'read' & 'show' is equivalent to the identity.
+isReversible :: (Eq r, Read r, Show r) => r -> Bool
+isReversible r	= read (show r) == r
diff --git a/src/ToolShed/Test/SelfValidate.hs b/src/ToolShed/Test/SelfValidate.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Test/SelfValidate.hs
@@ -0,0 +1,77 @@
+{-
+	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.SelfValidate".
+-}
+
+module ToolShed.Test.SelfValidate(
+-- * Types
+-- ** Data-types
+--	Primes,
+-- * Functions
+	quickChecks
+) where
+
+import			Control.Applicative((<$>))
+import qualified	Data.Foldable
+import qualified	Data.List
+import qualified	Data.Map
+import qualified	Data.Set
+import qualified	Test.QuickCheck
+import			Test.QuickCheck((==>))
+import qualified	ToolShed.SelfValidate	as SelfValidate
+import			ToolShed.Test.QuickCheck.Arbitrary.Map()
+import			ToolShed.Test.QuickCheck.Arbitrary.Set()
+
+-- | A test-type.
+newtype Primes	= MkPrimes Int	deriving (Eq, Ord, Show)
+
+instance SelfValidate.SelfValidator Primes	where
+	getErrors (MkPrimes i)	= SelfValidate.extractErrors [
+		(any ((== 0) . (i `rem`)) [2,3,5],	"Composite; " ++ show i),
+		(i < 0,					"Negative; " ++ show i),
+		(i `elem` [0, 1],			"Excluded; " ++ show i)
+	 ]
+
+instance Test.QuickCheck.Arbitrary Primes	where
+	arbitrary	= MkPrimes <$> Test.QuickCheck.elements [negate limit .. limit]	where limit = pred $ 7 * 7
+
+-- | Defines invariant properties.
+quickChecks :: IO ()
+quickChecks
+	= Test.QuickCheck.quickCheck `mapM_` [prop_list, prop_list']
+	>> Test.QuickCheck.quickCheck prop_set
+	>> Test.QuickCheck.quickCheck prop_map
+	where
+		prop_list :: [Primes] -> Test.QuickCheck.Property
+		prop_list l	= not (null l) ==> Test.QuickCheck.label "prop_list" $ SelfValidate.getErrors (head l) `Data.List.isPrefixOf` SelfValidate.getErrors l
+		prop_list' l	= Test.QuickCheck.label "prop_list'" $ all (
+			(`elem` map SelfValidate.getErrors l) . SelfValidate.getErrors
+		 ) l
+
+		prop_set :: Data.Set.Set Primes -> Test.QuickCheck.Property
+		prop_set s	= Test.QuickCheck.label "prop_set" $ Data.Foldable.all (
+			(`Data.Set.isSubsetOf` Data.Set.fromList (SelfValidate.getErrors s)) . Data.Set.fromList . SelfValidate.getErrors
+		 ) s
+
+		prop_map :: Data.Map.Map Int Primes -> Test.QuickCheck.Property
+		prop_map m	= Test.QuickCheck.label "prop_map" $ Data.Foldable.all (
+			(`Data.Set.isSubsetOf` Data.Set.fromList (SelfValidate.getErrors m)) . Data.Set.fromList . SelfValidate.getErrors
+		 ) m
+
diff --git a/toolshed.cabal b/toolshed.cabal
--- a/toolshed.cabal
+++ b/toolshed.cabal
@@ -1,6 +1,6 @@
 --Package-properties
 Name:			toolshed
-Version:		0.13.0.0
+Version:		0.14.0.0
 Cabal-Version:		>= 1.6
 Copyright:		(C) 2010 Dr. Alistair Ward
 License:		GPL
@@ -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
+Tested-With:		GHC == 6.10, GHC == 6.12, GHC == 7.0, GHC == 7.4
 Homepage:		http://functionalley.eu
 Maintainer:		toolshed <at> functionalley <dot> eu
 Bug-reports:		toolshed <at> functionalley <dot> eu
@@ -30,10 +30,7 @@
     hs-source-dirs:	src
 
     Exposed-modules:
-        ToolShed.Arbitrary.Array
-        ToolShed.Arbitrary.ArrayElem
-        ToolShed.Arbitrary.Map
-        ToolShed.Arbitrary.Set
+        ToolShed.Data.Foldable
         ToolShed.Data.List
         ToolShed.Data.List.Runlength
         ToolShed.Data.List.Splits
@@ -45,11 +42,19 @@
         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
 
     Build-depends:
         array,
         base == 4.*,
-        containers,
+        containers >= 0.4.2.0,
         directory,
         filepath,
         QuickCheck >= 2.2,
@@ -76,6 +81,7 @@
 
     Other-modules:
         ToolShed.Test.QuickChecks
+        ToolShed.Test.Data.Foldable
         ToolShed.Test.Data.List
         ToolShed.Test.Data.List.Runlength
         ToolShed.Test.Data.List.Splits
