diff --git a/Data/Ranges.hs b/Data/Ranges.hs
new file mode 100644
--- /dev/null
+++ b/Data/Ranges.hs
@@ -0,0 +1,40 @@
+{-# LANGUAGE FlexibleInstances #-}
+module Data.Ranges 
+(range, ranges, Range, Ranges, inRange, inRanges)
+where
+
+newtype Ord a => Range a = Range { unRange :: (a, a) }
+newtype Ord a => Ranges a = Ranges [Range a]
+
+-- | Construct a 'Range' from a lower and upper bound.
+range :: (Ord a) => a -> a -> Range a
+range l u
+	| l <= u = Range (l,u)
+	| otherwise = error "lower bound must be smaller than upper bound"
+
+-- | Construct a 'Ranges' from a list of lower and upper bounds.
+ranges :: (Ord a) => [(a,a)] -> Ranges a
+ranges = Ranges . map Range . foldr (\x xs -> map unRange $ mergeRanges (map Range xs) (uncurry range x)) []
+
+-- | Tests if a given range contains a particular value.
+inRange :: (Ord a) => a -> Range a -> Bool
+inRange x (Range (l,u)) = x >= l && x <= u
+
+-- | Tests if any of the ranges contains a particular value.
+inRanges :: (Ord a) => a -> Ranges a -> Bool
+inRanges x (Ranges xs) = or . map (x `inRange`) $ xs
+
+mergeRange :: (Ord a) => Range a -> Range a -> Either (Range a) (Range a)
+mergeRange x y
+	| lx <= uy && ux >= ly ||
+	  ly <= ux && uy >= lx = Right $ Range (min lx ly, max ux uy)
+	| otherwise = Left $ x
+	where 
+	(lx,ux) = unRange x
+	(ly,uy) = unRange y
+
+mergeRanges :: (Ord a) => [Range a] -> Range a -> [Range a]
+mergeRanges [] y = [y]
+mergeRanges (x:xs) y = case mergeRange x y of
+		Right z -> mergeRanges xs z
+		Left x -> x : (mergeRanges xs y)
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/ranges.cabal b/ranges.cabal
new file mode 100644
--- /dev/null
+++ b/ranges.cabal
@@ -0,0 +1,14 @@
+Name: ranges
+Version: 0.1
+Description: Ranges and various functions on them.
+License: BSD3
+Author: George Pollard <porges@porg.es>
+Maintainer: George Pollard <porges@porg.es>
+Build-Type: Simple
+Cabal-Version: >=1.2
+Category: data
+
+Library
+ Build-Depends: base
+ Exposed-modules: Data.Ranges
+ ghc-options: -O2 -Wall
