diff --git a/Data/Containers.hs b/Data/Containers.hs
new file mode 100644
--- /dev/null
+++ b/Data/Containers.hs
@@ -0,0 +1,733 @@
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleContexts, FlexibleInstances, TypeFamilies #-}
+-- TypeFamilies is only used for equality constraints
+
+{- |
+   Module      : Data.Containers
+   Description : Classes for different container types
+   Copyright   : Ivan Lazar Miljenovic
+   License     : 3-Clause BSD-style
+   Maintainer  : Ivan.Miljenovic@gmail.com
+
+-}
+module Data.Containers where
+
+import Prelude hiding ((!!), (++), elem, enumFrom, enumFromThen, enumFromTo, enumFromThenTo, all, and, any, break, concat, concatMap, cycle, drop, dropWhile, filter, foldl, foldl1, foldr, foldr1, head, init, iterate, last, length, lines, lookup, map, mapM, mapM_, maximum, minimum, notElem, null, or, product, repeat, replicate, reverse, scanl, scanl1, scanr, scanr1, sequence, sequence_, span, splitAt, sum, tail, take, takeWhile, unlines, unwords, unzip, unzip3, words, zip, zip3, zipWith, zipWith3, fmap)
+
+import qualified Prelude
+import Data.Char(isSpace)
+import qualified Data.List as List
+import Data.Maybe(fromMaybe)
+import Data.Monoid
+import Control.Monad(liftM2)
+
+infixl 9  !!
+infix  4 `elem`, `notElem`
+
+-- | 'Container's are data-types that store values.  No restriction is
+--   placed on /how/ they store these values, though there may be
+--   restrictions on some methods if a 'Container' is also an instance
+--   of a sub-class of 'Container'.
+--
+--   Minimum required implementation:
+--
+--     * 'null'
+--
+--     * 'insert'
+--
+--     * 'fold' or 'splitElem'
+class (Monoid c) => Container c v | c -> v where
+  -- | Test whether a 'Container' is empty.
+  null :: c -> Bool
+
+  -- | Create a singleton 'Container';
+  --   i.e. @'size' ('singleton' x) == 1@).
+  singleton   :: v -> c
+  singleton v = build ($v)
+
+  -- | Add a value to the 'Container'.  If this is also a 'Sequence',
+  --   then it should be a \"'cons'\" operation (i.e. insert the value
+  --   at the beginning of the 'Sequence').
+  insert :: v -> c -> c
+
+  -- | The container membership predicate, usually written in infix
+  --   form, e.g., @v `elem` c@.
+  elem :: (Eq v) => v -> c -> Bool
+  elem = any . (==)
+
+  -- | The negated version of 'elem'.
+  notElem   :: (Eq v) => v -> c -> Bool
+  notElem v = not . elem v
+
+  -- | Delete the first value of the 'Container' that matches the
+  --   predicate.
+  delete   :: (Eq v) => v -> c -> c
+  delete v = snd . fold delete' (False, empty)
+    where
+      delete' v' (False,c') | v' == v = (True, c')
+      delete' v' (flag, c') = (flag, v' `insert` c')
+
+  -- | Delete all values in the 'Container' that match the predicate.
+  deleteAll   :: (Eq v) => v -> c -> c
+  deleteAll v = filter (/=v)
+
+  -- | When applied to a predicate and a 'Container', 'filter' returns
+  --   the 'Container' containing just those elements that satisfy the
+  --   predicate (preserving order where applicable).
+  filter     :: (v -> Bool) -> c -> c
+  filter p c = build (\ ins nil ->
+                       fold (\ v c' -> if p v then v `ins` c' else c') nil c
+                     )
+
+  -- | Applied to a binary operator, a starting value and a
+  --   'Container', reduce the 'Container' using the binary operator.
+  --   For 'Sequence' instances, this should be a right fold.
+  fold       :: (v -> a -> a) -> a -> c -> a
+  fold f s c = case splitElem c of
+                 Nothing -> s
+                 Just (v,c') -> f v $ fold f s c'
+
+  -- | A variant of 'fold' with no starting value, and thus must be
+  --   applied to non-empty 'Container's.
+  fold1   :: (v -> v -> v) -> c -> v
+  fold1 f = fromMaybe err . fold f' Nothing
+    where
+      err = error "Container.fold1: empty container"
+      f' v Nothing   = Just v
+      f' v (Just v') = Just $ f v v'
+
+  -- | Returns the size of the 'Container'.
+  genericSize :: (Num n) => c -> n
+  genericSize = fold (const (($!) (+1))) 0
+
+  -- | Returns the size of the 'Container' as an 'Int'.  Typically
+  --   more efficient than 'genericSize'.
+  size :: c -> Int
+  size = genericSize
+
+  partition   :: (v -> Bool) -> c -> (c,c)
+  partition p = fold select (empty, empty)
+    where
+      select v ~(ts,fs) | p v       = (v `insert` ts, fs)
+                        | otherwise = (ts, v `insert` fs)
+
+  -- | Applied to a predicate and a 'Container', 'all' determines if
+  --   all elements of the 'Container' satisfy the predicate.
+  all   :: (v -> Bool) -> c -> Bool
+  all p = fold ((&&) . p) True
+
+  -- | Returns the conjunction of a 'Container' containing Boolean
+  --   values.  For the result to be 'True', the 'Container' must be
+  --   finite; 'False', however, results from a 'False' value
+  --   occurring within a finite position within the order utilised by
+  --   'fold'.
+  and :: (v ~ Bool) => c -> Bool
+  and = fold (&&) True
+
+  -- | Applied to a predicate and a 'Container', 'any' determines if
+  --   any element of the 'Container' satisfies the predicate.
+  any   :: (v -> Bool) -> c -> Bool
+  any p = fold ((||) . p) True
+
+  -- | Returns the disjunction of a 'Container' containing Boolean
+  --   values.  For the result to be 'False', the 'Container' must be
+  --   finite; 'True', however, results from a 'True' value
+  --   occurring within a finite position within the order utilised by
+  --   'fold'.
+  or :: (v ~ Bool) => c -> Bool
+  or = fold (||) False
+
+  -- | Computes the product of a finite 'Container' of numbers.
+  product :: (Num v) => c -> v
+  product = fold (*) 1
+
+  -- | Computes the sum of a finite 'Container' of numbers.
+  sum :: (Num v) => c -> v
+  sum = fold (+) 0
+
+  -- | A type-preserving mapping function, where the resulting
+  --   'Container' is obtained by applying the provided function on
+  --   every element of the 'Container'.  For instances of 'CFunctor',
+  --   @'rigidMap' = 'map'@ suffices.
+  rigidMap     :: (v -> v) -> c -> c
+  rigidMap f c = build (\ins nil -> fold (ins . f) nil c)
+
+  -- | An inverse to 'insert'.  Should obey the following:
+  --
+  --   * @isNothing ('splitElem' c) == 'null' c@
+  --
+  --   * If @'splitElem' c = 'Just' (v,c')@, then @c == v `'insert'` c'@.
+  --
+  --   * If @c@ is an instance of 'Sequence', then the returned value
+  --     should be the first one.
+  splitElem :: c -> Maybe (v, c)
+  splitElem = fold getFirst Nothing
+        where
+          getFirst v Nothing         = Just (v, empty)
+          getFirst v (Just (v', c')) = Just (v', v `insert` c')
+
+  -- | Returns the maximum value of a non-empty, finite 'Container'.
+  maximum :: (Ord v) => c -> v
+  maximum c
+    | null c    = error "Container.maximum: empty container"
+    | otherwise = fold1 max c
+
+  -- | Returns the minimum value of a non-empty, finite 'Container'.
+  minimum :: (Ord v) => c -> v
+  minimum c
+    | null c    = error "Container.minimum: empty container"
+    | otherwise = fold1 min c
+
+build   :: (Container c v) => ((v -> c -> c) -> c -> c) -> c
+build f = f insert empty
+
+-- | An alias for 'mempty'; constructs an empty 'Container'.
+empty :: (Container c v) => c
+empty = mempty
+
+-- | An alias for 'mappend'; combines two 'Container's.  For instances
+--   of 'Sequence' this should be an @append@ operation.
+(++) :: (Container c v) => c -> c -> c
+(++) = mappend
+
+-- | Concatenate all the inner 'Container's together.
+concat :: (Container o i, Container i v) => o -> i
+concat = fold (++) empty
+
+-- | Map a function over a 'Container' and concatenate the results.
+--   Note that the types of the initial and final 'Container's do not
+--   have to be the same.
+concatMap     :: (Container f fv, Container t tv) => (fv -> t) -> f -> t
+concatMap f c = build (\ ins nil -> fold ((++) . f) nil c)
+
+-- | Convert one 'Container' to another.  If they are both
+--   'Sequence's, then ordering is preserved.
+convertContainer :: (Container f v, Container t v) => f -> t
+convertContainer = convertContainerBy id
+
+-- | Convert one 'Container' to another by utilising a mapping
+--   function.  If they are both 'Sequence's, then ordering is
+--   preserved.
+convertContainerBy     :: (Container f fv, Container t tv)
+                          => (fv -> tv) -> f -> t
+convertContainerBy f c = build (\ ins nil -> fold (ins . f) nil c)
+
+-- | Denotes 'Container's that have kind @* -> *@ and can thus have
+--   more than one possible type of value stored within them.
+class (Container (c a) a) => CFunctor c a where
+  -- | Apply the provided function on every element of the 'Container'.
+  map :: (CFunctor c b) => (a -> b) -> c a -> c b
+  map = convertContainerBy
+
+-- | Evaluate each action in the 'Container' and collect the results.
+--   The order the actions are evaluated in are determined by the
+--   corresponding 'fold' definition.
+sequence :: (Monad m, CFunctor c a, CFunctor c (m a)) => c (m a) -> m (c a)
+sequence = mapM id
+
+-- | Evaluate each action in the 'Container' and discard the results.
+--   The order the actions are evaluated in are determined by the
+--   corresponding 'fold' definition.
+sequence_ :: (Monad m, Container c (m a)) => c -> m ()
+sequence_ = fold (>>) (return ())
+-- Can't use "mapM_ id" as it requires an internal container and thus
+-- constrains the type more.
+
+-- | Apply the monadic mapping function to all the elements of the
+--   'Container, and then evaluate the actions and collect the
+--   results.  The order the actions are evaluated in are determined
+--   by the corresponding 'fold' definition.
+mapM   :: (Monad m, CFunctor c a, CFunctor c b) => (a -> m b) -> c a -> m (c b)
+mapM f = fold (liftM2 insert . f) (return empty)
+-- By not using sequence, we remove the requirement of the extra internal constraint
+
+-- | Apply the monadic mapping function to all the elements of the
+--   'Container, and then evaluate the actions and discard the
+--   results.  The order the actions are evaluated in are determined
+--   by the corresponding 'fold' definition.
+mapM_   :: (Monad m, CFunctor c a) => (a -> m b) -> c a -> m ()
+mapM_ f = fold ((>>) . f) (return ())
+
+-- -----------------------------------------------------------------------------
+
+-- | 'Sequence's are linear 'Container's with explicit left (start)
+--   and right (end) ends.  As such, it is possible to append/traverse
+--   from either end.
+--
+--   All methods have default stand-alone definitions, and thus no
+--   explicit method definitions are required for instances.
+class (Container c v) => Sequence c v where
+  -- | Append the value to the end of the 'Sequence'.
+  snoc     :: c -> v -> c
+  snoc c v = c ++ singleton v
+
+  -- | Applied to a binary operator, a starting value and a
+  --   'Sequence', reduce the 'Sequence' using the binary operator
+  --   from left to right.
+  --
+  --   The default definition is modelled after 'Data.List.foldl''
+  --   rather than 'Data.List.foldl'.
+  foldl :: (b -> v -> b) -> b -> c -> b
+  foldl f s c = case viewL c of
+                  Nothing -> s
+                  Just (v,c') -> let s' = f s v
+                                 in s' `seq` foldl f s' c'
+
+  -- | A variant of 'foldl' with no starting value, and thus must be
+  --   applied to non-empty 'Sequences's.
+  foldl1   :: (v -> v -> v) -> c -> v
+  foldl1 f = fromMaybe err . foldl f' Nothing
+    where
+      err = error "Sequence.foldl1: empty sequence"
+      f' Nothing   v = Just v
+      f' (Just v') v = Just $ f v' v
+
+  -- | An inverse to 'snoc' (equivalent to @('init' xs, 'last xs')@
+  --   for non-empty 'Sequence's).  Should obey the following:
+  --
+  --   * @isNothing ('viewR' xs) == 'null' xs@
+  --
+  --   * If @'viewR' xs = 'Just' (x,xs')@, then @xs == xs' `'snoc'` x@.
+  viewR :: c -> Maybe (v, c)
+  viewR = foldl getLast Nothing
+    where
+      getLast Nothing         v = Just (v, empty)
+      getLast (Just (v', c')) v = Just (v', c' `snoc` v)
+
+  -- | The first element of a non-empty 'Sequence'.
+  head :: (Sequence c v) => c -> v
+  head = maybe err fst . viewL
+    where
+      err = error "Sequence.head: empty sequence"
+
+  -- | Everything except the first element of a non-empty 'Sequence'.
+  --   Consider instead using 'drop 1'.
+  tail :: (Sequence c v) => c -> c
+  tail = maybe err snd . viewL
+    where
+      err = error "Sequence.tail: empty sequence"
+
+  -- | The last element of a non-empty 'Sequence'.
+  last :: (Sequence c v) => c -> v
+  last = maybe err fst . viewR
+    where
+      err = error "Sequence.last: empty sequence"
+
+  -- | Everything except the last value of a non-empty 'Sequence'.
+  init :: (Sequence c v) => c -> c
+  init = maybe err snd . viewR
+    where
+      err = error "Sequence.init: empty sequence"
+
+  -- | Return the first @n@ elements of a 'Sequence', or the entire
+  --   'Sequence' if its 'length' is less than @n@.
+  genericTake   :: (Integral n) => n -> c -> c
+  genericTake l = go l . viewL
+    where
+      go n _ | n <= 0  = empty
+      go _ Nothing     = empty
+      go n (Just(v,c')) = v `cons` go (n-1) (viewL c')
+
+  -- | A variant of 'genericTake' where @n@ has to be an 'Int', and is
+  --   usually more efficient.
+  take :: Int -> c -> c
+  take = genericTake
+
+  -- | When applied to a predicate @p@ and a 'Sequence' @xs@, returns
+  --   the longest prefix (possibly empty) of @xs@ of elements that
+  --   satisfy @p@.
+  takeWhile   :: (v -> Bool) -> c -> c
+  takeWhile p = go . viewL
+    where
+      go Nothing = empty
+      go (Just(v,c))
+        | p v       = v `cons` go (viewL c)
+        | otherwise = empty
+
+  -- | @'dropWhile' p xs@ returns the suffix remaining after
+  --   @'takeWhile' p xs@.
+  dropWhile     :: (v -> Bool) -> c -> c
+  dropWhile p c = build (go (viewL c))
+    where
+      go Nothing     _   nil = nil
+      go (Just(v,c)) ins nil
+        | p v       = go (viewL c) ins nil
+        | otherwise = v `ins` c
+
+  -- | @'genericDrop' n xs@ returns the suffix of @xs@ after the first
+  --   @n@ elements, or 'empty' if @n > 'length' xs@.
+  genericDrop     :: (Integral n) => n -> c -> c
+  genericDrop l c = build (go l (viewL c))
+    where
+      go _ Nothing     _   nil = nil
+      go n (Just(_,c)) ins nil
+        | n <= 0    = nil
+        | otherwise = go (n-1) (viewL c) ins nil
+
+  -- | A variant of 'genericDrop' where @n@ has to be an 'Int', and is
+  --   usually more efficient.
+  drop :: Int -> c -> c
+  drop = genericDrop
+
+  -- | @'reverse' xs@ returns the elements of @xs@ in reverse order.
+  --   @xs@ must be finite.
+  reverse   :: c -> c
+  reverse c = build (\ ins nil -> foldl (flip ins) nil c)
+
+  -- | When applied to a predicate @p@ and a 'Sequence' @xs@, returns
+  --   a tuple where first element is longest prefix (possibly empty)
+  --   of @xs@ of elements that satisfy p and second element is the
+  --   remainder of the 'Sequence'.
+  span   :: (v -> Bool) -> c -> (c,c)
+  span p = go . viewL
+    where
+      go Nothing = (empty, empty)
+      go (Just(v,c))
+        | p v       = let (t,f) = go (viewL c) in (v `cons` t, f)
+        | otherwise = (empty, v `cons` c)
+
+  -- | When applied to a predicate @p@ and a 'Sequence' @xs@, returns
+  --   a tuple where first element is longest prefix (possibly empty)
+  --   of @xs@ of elements that /do not satisfy/ p and second element
+  --   is the remainder of the 'Sequence'.
+  --
+  --    @'break' p@ is equivalent to @'span' ('not' . p)@.
+  break :: (v -> Bool) -> c -> (c,c)
+  break = span . (not .)
+
+  -- | @'genericSplitAt' n xs@ returns a tuple where the first element
+  --   is the prefix of 'length' @n@ of @xs@ and the second element is
+  --   the rest of the 'Sequence'.  It is equivalent to
+  --   @('genericTake' n xs, 'genericDrop' n xs)@.
+  genericSplitAt   :: (Integral n) => n -> c -> (c,c)
+  genericSplitAt n c = (genericTake n c, genericDrop n c)
+
+  -- | A variant of 'genericSplitAt' where @n@ has to be an 'Int', and
+  --   is usually more efficient.
+  splitAt     :: Int -> c -> (c,c)
+  splitAt n c = (take n c, drop n c)
+
+  -- | @'genericReplicate' n x@ is a 'Sequence' of length @n@ where
+  --   every element is @x@.
+  genericReplicate     :: (Integral n) => n -> v -> c
+  genericReplicate l v = build (go l)
+    where
+      go n _   nil | n <= 0 = nil
+      go n ins nil = v `ins` go (n-1) ins nil
+
+  -- | A variant of 'genericReplicate' where @n@ has to be an 'Int',
+  --   and is usually more efficient.
+  replicate :: Int -> v -> c
+  replicate = genericReplicate
+
+  -- | 'lines' breaks a string up into a 'Sequence' of 'Strings' at
+  --   newline characters. The resulting 'Strings' do not contain
+  --   newlines.
+  lines :: (v ~ String) => String -> c
+  lines = build . go
+    where
+      go "" _   nil = nil
+      go s  ins nil = let (l, s') = Prelude.break (== '\n') s
+                      in l `ins` case s' of
+                                   ""      -> nil
+                                   (_:s'') -> go s'' ins nil
+
+  -- | 'unlines' is an inverse operation to 'lines'. It joins lines,
+  --   after appending a terminating newline to each.
+  unlines :: (v ~ String) => c -> String
+  unlines = go . viewL
+    where
+      go Nothing = ""
+      go (Just(l,ls)) = l Prelude.++ '\n' : go (viewL ls)
+
+  -- | 'words' breaks a 'String' up into a 'Sequence' of words, which
+  --   were delimited by white space.
+  words :: (v ~ String) => String -> c
+  words = build . go
+    where
+      go s ins nil = case Prelude.dropWhile isSpace s of
+                       "" -> nil
+                       s' -> let (w,s'') = Prelude.break isSpace s'
+                             in w `ins` go s'' ins nil
+
+  -- | 'unwords' is an inverse operation to 'words'. It joins words
+  --   with separating spaces.
+  unwords :: (v ~ String) => c -> String
+  unwords = go . viewL
+    where
+      go Nothing       = ""
+      go (Just(fw,ws)) = go' fw $ viewL ws
+        where
+          go' w Nothing        = w
+          go' w (Just(w',ws')) = w Prelude.++ ' ' : go' w' (viewL ws')
+
+
+buildL   :: (Sequence c v) => ((c -> v -> c) -> c -> c) -> c
+buildL f = f snoc empty
+
+-- | An alias for 'insert' for 'Sequence's.
+cons :: (Sequence c v) => v -> c -> c
+cons = insert
+
+-- | An alias for 'genericSize' for 'Sequence's.
+genericLength :: (Sequence c v, Integral n) => c -> n
+genericLength = genericSize
+
+-- | An alias for 'size' for 'Sequence's.
+length :: (Sequence c v) => c -> Int
+length = size
+
+-- | An alias for 'fold' for 'Seuquence's.
+foldr :: (Sequence c v) => (v -> a -> a) -> a -> c -> a
+foldr = fold
+
+-- | An alias for 'fold1' for 'Seuquence's.
+foldr1 :: (Sequence c v) => (v -> v -> v) -> c -> v
+foldr1 = fold1
+
+-- | An alias for 'splitElem' for 'Seuquence's.
+viewL :: (Sequence c v) => c -> Maybe (v,c)
+viewL = splitElem
+
+-- | 'Sequence' index (subscript) operator, starting from 0.  Will
+--    throw an 'error' if the index is negative or larger than the
+--    length of the 'Sequence'.
+(!!) :: (Sequence c v) => c -> Int -> v
+_ !! n | n < 0 = error "Sequence.(!!): negative index"
+c !! n = maybe err fst . viewL $ drop (n-1) c
+  where
+    err = error "Sequence.(!!): index too large"
+
+-- | Represents 'Sequence's that are also instances of 'CFunctor'.
+--   All methods have default definitions.
+class (Sequence (c a) a, CFunctor c a) => SFunctor c a where
+  scanl     :: (SFunctor c b) => (b -> a -> b) -> b -> c a -> c b
+  scanl f b =  build . go b
+    where
+      go v c ins nil = v `ins`
+                       case viewL c of
+                         Nothing -> nil
+                         Just (v',c') -> go (f v v') c ins nil
+
+  scanl1   :: (a -> a -> a) -> c a -> c a
+  scanl1 f = maybe (build (const id)) (uncurry (scanl f)) . viewL
+
+  scanr     :: (SFunctor c b) => (a -> b -> b) -> b -> c a -> c b
+  scanr f b = build . go . viewL
+    where
+      go Nothing     _   _   = singleton b
+      go (Just(v,c)) ins nil = f v (head c') `ins` c'
+        where
+          c' = go (viewL c) ins nil
+
+  scanr1   :: (a -> a -> a) -> c a -> c a
+  scanr1 f = maybe (build (const id)) (uncurry (scanr f)) . viewL
+
+  zipWith         :: (SFunctor c b, SFunctor c d)
+                     => (a -> b -> d) -> c a -> c b -> c d
+  zipWith f ca cb = build $ wrap ca cb
+    where
+      wrap ca' cb' = go (viewL ca') (viewL cb')
+      go (Just(a,ca')) (Just(b,cb')) ins nil = f a b `ins` wrap ca' cb' ins nil
+      go _             _             _   nil = nil
+
+  zip :: (SFunctor c b, SFunctor c (a,b)) => c a -> c b -> c (a,b)
+  zip = zipWith (,)
+
+  unzip :: (SFunctor c b, SFunctor c (a,b)) => c (a,b) -> (c a, c b)
+  unzip = fold f (empty,empty)
+    where
+      f (a,b) ~(ca,cb) = (a `cons` ca, b `cons` cb)
+
+  zipWith3            :: (SFunctor c b, SFunctor c d, SFunctor c e)
+                         => (a -> b -> d -> e) -> c a -> c b -> c d -> c e
+  zipWith3 f ca cb cd = build $ wrap ca cb cd
+    where
+      wrap ca' cb' cd' = go (viewL ca') (viewL cb') (viewL cd')
+      go (Just(a,ca')) (Just(b,cb')) (Just(d,cd')) ins nil = f a b d
+                                                             `ins`
+                                                             wrap ca' cb' cd' ins nil
+      go _             _             _             _   nil = nil
+
+  zip3 :: (SFunctor c b, SFunctor c d, SFunctor c (a,b,d))
+         => c a -> c b -> c d -> c (a,b,d)
+  zip3 = zipWith3 (,,)
+
+  unzip3 :: (SFunctor c b, SFunctor c d, SFunctor c (a,b,d))
+            => c (a,b,d) -> (c a, c b, c d)
+  unzip3 = fold f (empty,empty,empty)
+    where
+      f (a,b,d) ~(ca,cb,cd) = (a `cons` ca, b `cons` cb, d `cons` cd)
+
+-- -----------------------------------------------------------------------------
+
+-- | Represents 'Sequence's that may be infinite in length.  All
+--   methods have default definitions.
+class (Sequence c v) => Stream c v where
+  -- | @'repeat' x@ is an infinite 'Stream', with @x@ the value of
+  --   every element.
+  repeat   :: v -> c
+  repeat v = v `cons` repeat v
+
+  -- | 'cycle' ties a finite 'Stream' into a circular one, or
+  --   equivalently, the infinite repetition of the original 'Stream'.
+  --   It is the identity on infinite 'Stream's.
+  cycle :: c -> c
+  cycle = checkNull
+    where
+      checkNull c
+        | null c    = error "Stream.cycle: empty stream"
+        | otherwise = go c
+      go c = c ++ go c
+
+  -- | @'iterate' f x@ returns an infinite 'Stream' of repeated
+  --   applications of @f@ to @x@:
+  --
+  --   > iterate f x = x `cons` f x `cons` f (f x) `cons` ...
+  iterate   :: (v -> v) -> v -> c
+  iterate f = build . go
+    where
+      go x ins nil = x `ins` go (f x) ins nil
+
+-- | A wrapper around 'Prelude.enumFrom'.
+enumFrom :: (Enum a, Stream c a) => a -> c
+enumFrom = convertContainer . Prelude.enumFrom
+
+-- | A wrapper around 'Prelude.enumFromThen'.
+enumFromThen      :: (Enum a, Stream c a) => a -> a -> c
+enumFromThen f th = convertContainer $ Prelude.enumFromThen f th
+
+-- | A wrapper around 'Prelude.enumFromThenTo'.
+enumFromThenTo        :: (Enum a, Sequence c a) => a -> a -> a -> c
+enumFromThenTo f th t = convertContainer $ Prelude.enumFromThenTo f th t
+
+-- | A wrapper around 'Prelude.enumFromTo'.
+enumFromTo     :: (Enum a, Sequence c a) => a -> a -> c
+enumFromTo f t = convertContainer $ Prelude.enumFromTo f t
+
+-- -----------------------------------------------------------------------------
+
+instance Container [a] a where
+  null = Prelude.null
+
+  -- Use default to have build be used
+  -- singleton = (:[])
+
+  insert = (:)
+
+  elem = Prelude.elem
+
+  notElem = Prelude.notElem
+
+  delete = List.delete
+
+  -- No pre-defined deleteAll equivalent
+
+  filter = Prelude.filter
+
+  fold = Prelude.foldr
+
+  fold1 = Prelude.foldr1
+
+  genericSize = List.genericLength
+
+  size = Prelude.length
+
+  partition = List.partition
+
+  all = Prelude.all
+
+  and = Prelude.and
+
+  any = Prelude.any
+
+  or = Prelude.or
+
+  product = Prelude.product
+
+  sum = Prelude.sum
+
+  rigidMap = map
+
+  splitElem []     = Nothing
+  splitElem (a:as) = Just (a,as)
+
+  maximum = Prelude.maximum
+
+  minimum = Prelude.minimum
+
+instance CFunctor [] a where
+  map = Prelude.map
+
+instance Sequence [a] a where
+  -- snoc can stay as is
+
+  foldl = List.foldl'
+
+  foldl1 = List.foldl1'
+
+  -- Get the laziness into it
+  viewR [] = Nothing
+  viewR as = Just (last as, init as)
+
+  head = Prelude.head
+
+  tail = Prelude.tail
+
+  last = Prelude.last
+
+  init = Prelude.init
+
+  genericTake = List.genericTake
+
+  take = Prelude.take
+
+  takeWhile = Prelude.takeWhile
+
+  dropWhile = Prelude.dropWhile
+
+  genericDrop = List.genericDrop
+
+  drop = Prelude.drop
+
+  reverse = Prelude.reverse
+
+  span = Prelude.span
+
+  break = Prelude.break
+
+  genericSplitAt = List.genericSplitAt
+
+  splitAt = Prelude.splitAt
+
+  genericReplicate = List.genericReplicate
+
+  replicate = Prelude.replicate
+
+  lines = Prelude.lines
+
+  unlines = Prelude.unlines
+
+  words = Prelude.words
+
+  unwords = Prelude.unwords
+
+instance SFunctor [] a where
+  scanl = Prelude.scanl
+
+  scanl1 = Prelude.scanl1
+
+  scanr = Prelude.scanr
+
+  scanr1 = Prelude.scanr1
+
+  zip = Prelude.zip
+
+  zipWith = Prelude.zipWith
+
+  unzip = Prelude.unzip
+
+  zip3 = Prelude.zip3
+
+  zipWith3 = Prelude.zipWith3
+
+  unzip3 = Prelude.unzip3
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,33 @@
+Copyright (c) 2010, Ivan Lazar Miljenovic
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Ivan Lazar Miljenovic nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+This library uses code based upon that of the Glasgow Haskell Compiler
+(GHC): http://haskell.org/ghc/
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/container-classes.cabal b/container-classes.cabal
new file mode 100644
--- /dev/null
+++ b/container-classes.cabal
@@ -0,0 +1,21 @@
+Name:                container-classes
+Version:             0.0.0.0
+Synopsis:            Generic classes for interacting with different container types
+Description:         Allow users of your library to choose which data
+                     structure they want to use rather than
+                     constraining them to whatever you chose at the
+                     time.
+License:             BSD3
+License-file:        LICENSE
+Author:              Ivan Lazar Miljenovic
+Maintainer:          Ivan.Miljenovic@gmail.com
+Copyright:           Ivan Lazar Miljenovic
+Category:            Data Structures
+Build-type:          Simple
+-- Extra-source-files:
+Cabal-Version:       >=1.2
+
+
+Library
+  Exposed-modules:     Data.Containers
+  Build-Depends:       base < 5
