diff --git a/ClassyPrelude.hs b/ClassyPrelude.hs
--- a/ClassyPrelude.hs
+++ b/ClassyPrelude.hs
@@ -4,106 +4,8 @@
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE TypeFamilies #-}
 module ClassyPrelude
-    ( -- * Standard
-      -- ** Operators
-      (Prelude.$)
-    , (Prelude.+)
-    , (Prelude.-)
-    , (Prelude.*)
-    , (Prelude./)
-    , (Prelude.&&)
-    , (Prelude.||)
-    , (Prelude..)
-      -- ** Functions
-    , Prelude.not
-    , Prelude.otherwise
-    , Prelude.fst
-    , Prelude.snd
-    , Prelude.id
-    , Prelude.maybe
-    , Prelude.either
-    , Prelude.flip
-    , Prelude.const
-    , Prelude.error
-    , Prelude.zip
-    , Prelude.unzip
-    , Prelude.zipWith
-    , Prelude.or
-    , Data.Text.IO.putStrLn
-    , Prelude.elem
-    , Prelude.odd
-    , Prelude.even
-    , Prelude.uncurry
-      -- ** Type classes
-    , Prelude.Ord (..)
-    , Prelude.Eq (..)
-    , Prelude.Enum (..)
-    , Prelude.Show
-    , Prelude.Functor (..)
-    , Prelude.Monad (..)
-    , (Control.Monad.=<<)
-      -- ** Data types
-    , Prelude.Maybe (..)
-    , Prelude.Ordering (..)
-    , Prelude.Bool (..)
-    , Prelude.Char
-    , Prelude.IO
-    , Prelude.Either (..)
-    , Prelude.Integral (..)
-      -- * Re-exports
-      -- ** Packed reps
-    , ByteString
-    , LByteString
-    , Text
-    , LText
-      -- ** Containers
-    , Map
-    , HashMap
-    , LHashMap
-    , Set
-    , HashSet
-    , Vector
-      -- ** Numbers
-    , Word8
-    , Word64
-    , Int64
-    , Prelude.Int
-    , Word
-      -- ** Monoids
-    , Monoid (..)
-    , concat
-    , (++)
-      -- ** Arrow
-    , Control.Arrow.first
-    , Control.Arrow.second
-    , (Control.Arrow.***)
-    , (Control.Arrow.&&&)
-      -- ** Maybe
-    , Data.Maybe.mapMaybe
-    , Data.Maybe.catMaybes
-    , Data.Maybe.fromMaybe
-      -- ** Either
-    , Data.Either.partitionEithers
-      -- ** Applicative
-    , Control.Applicative.Applicative (..)
-    , (Control.Applicative.<$>)
-      -- ** Monad
-    , (Control.Monad.>=>)
-      -- ** Transformers
-    , Control.Monad.Trans.Class.lift
-    , Control.Monad.IO.Class.MonadIO
-    , Control.Monad.IO.Class.liftIO
-      -- ** Exceptions
-    , Control.Exception.Exception (..)
-    , Control.Exception.SomeException
-    , Control.Exception.throwIO
-      -- ** Files
-    , F.FilePath
-    , (F.</>)
-    , (F.<.>)
-    , F.hasExtension
-    , F.basename
-    , F.filename
+    ( -- * CorePrelude
+      module CorePrelude
       -- * Non-standard
       -- ** List-like classes
     , map
@@ -114,20 +16,31 @@
     , null
     , pack
     , unpack
+    , repack
     , fromList
     , toList
     , mapM
     , mapM_
-    , empty
     , stripPrefix
+    , isPrefixOf
+    , stripSuffix
+    , isSuffixOf
+    , isInfixOf
     , break
     , span
     , dropWhile
     , takeWhile
     , any
     , all
-    , splitAt
+    , splitAt, take, drop
     , fold
+    , words
+    , unwords
+    , lines
+    , unlines
+    , split
+    , reverse
+    , readMay
       -- ** Map-like
     , lookup
     , insert
@@ -139,54 +52,28 @@
       -- ** Files
     , readFile
     , writeFile
-      -- ** Print
-    , Prelude.print
     ) where
 
 import qualified Prelude
-import Prelude (Char, (.))
-
-import ClassyPrelude.Classes
-import ClassyPrelude.List ()
-import ClassyPrelude.ByteString
-import ClassyPrelude.LByteString
-import ClassyPrelude.Text
-import ClassyPrelude.LText
-import ClassyPrelude.Map
-import ClassyPrelude.Set
-import ClassyPrelude.FilePath ()
-import ClassyPrelude.Vector
-import ClassyPrelude.HashMap
-import ClassyPrelude.LHashMap
-import ClassyPrelude.HashSet
-
-import Data.Monoid (Monoid (..))
-import qualified Control.Arrow
-import qualified Control.Applicative
-import qualified Control.Monad
-import qualified Control.Exception
-
-import qualified Filesystem.Path.CurrentOS as F
-
-import Data.Word (Word8, Word64, Word)
-import Data.Int (Int64)
-
-import qualified Data.Text.IO
-
 import qualified Data.Maybe
-import qualified Data.Either
 
-import qualified Control.Monad.Trans.Class
-import qualified Control.Monad.IO.Class
-
-concat :: Monoid w => [w] -> w
-concat = mconcat
+import CorePrelude
+import ClassyPrelude.Classes
 
-infixr 5  ++
-(++) :: Monoid w => w -> w -> w
-(++) = mappend
+import ClassyPrelude.ByteString ()
+import ClassyPrelude.Classes ()
+import ClassyPrelude.FilePath ()
+import ClassyPrelude.HashMap ()
+import ClassyPrelude.HashSet ()
+import ClassyPrelude.LByteString ()
+import ClassyPrelude.LText ()
+import ClassyPrelude.List ()
+import ClassyPrelude.Map ()
+import ClassyPrelude.Set ()
+import ClassyPrelude.Text ()
+import ClassyPrelude.Vector ()
 
-show :: (Prelude.Show a, CanPack c Prelude.Char) => a -> c
+show :: (Prelude.Show a, CanPack c Char) => a -> c
 show = pack . Prelude.show
 
 fromList :: CanPack c i => [i] -> c
@@ -199,3 +86,15 @@
 instance CanPack (Prelude.Maybe a) a where
     pack = Data.Maybe.listToMaybe
     unpack = Data.Maybe.maybeToList
+
+readMay :: (Prelude.Read b, CanPack a Char) => a -> Maybe b
+readMay a =
+    case [x | (x, t) <- Prelude.reads (unpack a), null t] of
+        [x] -> Just x
+        _ -> Nothing
+
+-- | Repack from one type to another, dropping to a list in the middle.
+--
+-- @repack = pack . unpack@.
+repack :: (CanPack a i, CanPack b i) => a -> b
+repack = pack . unpack
diff --git a/ClassyPrelude/ByteString.hs b/ClassyPrelude/ByteString.hs
--- a/ClassyPrelude/ByteString.hs
+++ b/ClassyPrelude/ByteString.hs
@@ -15,11 +15,11 @@
 import qualified Filesystem.Path.CurrentOS as F
 import Data.Word (Word8)
 
-instance (co ~ ByteString, i ~ Word8, o ~ Word8) => CanMapFunc ByteString co i o where
+instance CanMapFunc ByteString ByteString Word8 Word8 where
     mapFunc = S.map
-instance (co ~ ByteString, i ~ Word8, o ~ ByteString) => CanConcatMapFunc ByteString co i o where
+instance CanConcatMapFunc ByteString ByteString Word8 ByteString where
     concatMapFunc = S.concatMap
-instance CanFilterFunc ByteString Word8 where
+instance CanFilterFunc ByteString ByteString Word8 where
     filterFunc = S.filter
 instance CanLength ByteString Prelude.Int where
     length = S.length
@@ -30,8 +30,6 @@
 instance CanPack ByteString Word8 where
     pack = S.pack
     unpack = S.unpack
-instance CanEmpty ByteString where
-    empty = S.empty
 instance MonadIO m => CanReadFile (m ByteString) where
     readFile = liftIO . S.readFile . F.encodeString
 instance CanWriteFileFunc ByteString where
@@ -46,3 +44,12 @@
     all = S.all
 instance CanSplitAt ByteString Prelude.Int where
     splitAt = S.splitAt
+
+instance CanReverse ByteString where
+    reverse = S.reverse
+
+instance CanFoldFunc ByteString Word8 accum where
+    foldFunc = S.foldl'
+
+instance CanReplicate ByteString Word8 Prelude.Int where
+    replicate = S.replicate
diff --git a/ClassyPrelude/Classes.hs b/ClassyPrelude/Classes.hs
--- a/ClassyPrelude/Classes.hs
+++ b/ClassyPrelude/Classes.hs
@@ -1,36 +1,38 @@
 {-# LANGUAGE NoImplicitPrelude #-}
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE TypeFamilies #-}
 module ClassyPrelude.Classes where
 
 import qualified Prelude
+import Prelude (Monad)
 import qualified Filesystem.Path.CurrentOS as F
 import Control.Monad.IO.Class (MonadIO)
 
 class CanMap f i o where
     map :: (i -> o) -> f
-class CanMapFunc ci co i o where
+class CanMapFunc ci co i o | ci -> i, co -> o, ci o -> co, co i -> ci where
     mapFunc :: (i -> o) -> ci -> co
 instance CanMapFunc ci co i o => CanMap (ci -> co) i o where
     map = mapFunc
 
 class CanConcatMap f i o where
     concatMap :: (i -> o) -> f
-class CanConcatMapFunc ci co i o where
+class CanConcatMapFunc ci co i o | ci -> i, co -> o, ci o -> co, co i -> ci where
     concatMapFunc :: (i -> o) -> ci -> co
 instance CanConcatMapFunc ci co i o => CanConcatMap (ci -> co) i o where
     concatMap = concatMapFunc
 
-class CanFilter f a where
-    filter :: (a -> Prelude.Bool) -> f
-class CanFilterFunc c i | c -> i where
-    filterFunc :: (i -> Prelude.Bool) -> c -> c
-instance (b ~ c, CanFilterFunc b a) => CanFilter (b -> c) a where
+class CanFilter f i where
+    filter :: (i -> Prelude.Bool) -> f
+class CanFilterFunc ci co i | ci -> i co where
+    filterFunc :: (i -> Prelude.Bool) -> ci -> co
+instance (CanFilterFunc ci co i) => CanFilter (ci -> co) i where
     filter = filterFunc
 
-class CanLength c i | c -> i where
-    length :: c -> i
+class CanLength c len | c -> len where
+    length :: c -> len
 
 class CanSingleton c i | c -> i where
     singleton :: i -> c
@@ -42,26 +44,23 @@
     pack :: [i] -> c
     unpack :: c -> [i]
 
-class CanMapM f i o m where
+class Monad m => CanMapM f m i o where
     mapM :: (i -> m o) -> f
-class CanMapMFunc ci co i o m where
-    mapMFunc :: (i -> m o) -> ci -> m co
-instance CanMapMFunc ci co i o m => CanMapM (ci -> m co) i o m where
+class Monad m => CanMapMFunc ci mco m i o | ci -> i, mco -> m o, ci o m -> mco, mco i -> ci where
+    mapMFunc :: (i -> m o) -> ci -> mco
+instance CanMapMFunc ci mco m i o => CanMapM (ci -> mco) m i o where
     mapM = mapMFunc
 
-class CanMapM_ f i o m where
+class Monad m => CanMapM_ f m i where
     mapM_ :: (i -> m o) -> f
-class CanMapM_Func ci i o m where
-    mapM_Func :: (i -> m o) -> ci -> m ()
-instance CanMapM_Func ci i o m => CanMapM_ (ci -> m ()) i o m where
+class CanMapM_Func ci i | ci -> i where
+    mapM_Func :: Monad m => (i -> m o) -> ci -> m ()
+instance (Monad m, CanMapM_Func ci i, r ~ m ()) => CanMapM_ (ci -> r) m i where
     mapM_ = mapM_Func
 
 class CanLookup c k v | c -> k v where
     lookup :: k -> c -> Prelude.Maybe v
 
-class CanEmpty c where
-    empty :: c
-
 class CanInsert f where
     insert :: f
 class CanInsertVal c k v | c -> k v where
@@ -87,6 +86,7 @@
 
 class CanStripPrefix a where
     stripPrefix :: a -> a -> Prelude.Maybe a
+    isPrefixOf :: a -> a -> Prelude.Bool
 
 class CanBreak c i | c -> i where
     break :: (i -> Prelude.Bool) -> c -> (c, c)
@@ -101,10 +101,38 @@
 class CanSplitAt c i | c -> i where
     splitAt :: i -> c -> (c, c)
 
-class CanFold accum a f where
+take :: CanSplitAt c i => i -> c -> c
+take i c  = Prelude.fst (splitAt i c)
+drop :: CanSplitAt c i => i -> c -> c
+drop i c  = Prelude.snd (splitAt i c)
+
+class CanFold f i accum where
     -- | Strict left fold.
-    fold :: (accum -> a -> accum) -> accum -> f
-class CanFoldFunc c accum a | c -> a where
-    foldFunc :: (accum -> a -> accum) -> accum -> c -> accum
-instance (accum ~ accum', CanFoldFunc c accum a) => CanFold accum a (c -> accum') where
+    fold :: (accum -> i -> accum) -> accum -> f
+class CanFoldFunc c i accum | c -> i where
+    -- | Strict left fold.
+    foldFunc :: (accum -> i -> accum) -> accum -> c -> accum
+instance (CanFoldFunc c i accum, accum ~ result) => CanFold (c -> result) i accum where
     fold = foldFunc
+
+class CanWords t where
+    words :: t -> [t]
+    unwords :: [t] -> t
+    lines :: t -> [t]
+    unlines :: [t] -> t
+
+class CanSplit c i | c -> i where
+    split :: (i -> Prelude.Bool) -> c -> [c]
+
+class CanStripSuffix a where
+    stripSuffix :: a -> a -> Prelude.Maybe a
+    isSuffixOf :: a -> a -> Prelude.Bool
+
+class CanIsInfixOf a where
+    isInfixOf :: a -> a -> Prelude.Bool
+
+class CanReverse a where
+    reverse :: a -> a
+
+class CanReplicate a i len | a -> i len where
+    replicate :: len -> i -> a
diff --git a/ClassyPrelude/FilePath.hs b/ClassyPrelude/FilePath.hs
--- a/ClassyPrelude/FilePath.hs
+++ b/ClassyPrelude/FilePath.hs
@@ -14,3 +14,7 @@
     unpack = F.encodeString
 instance CanStripPrefix F.FilePath where
     stripPrefix = F.stripPrefix
+    isPrefixOf a b =
+        case stripPrefix a b of
+            Prelude.Nothing -> Prelude.False
+            Prelude.Just{} -> Prelude.True
diff --git a/ClassyPrelude/HashMap.hs b/ClassyPrelude/HashMap.hs
--- a/ClassyPrelude/HashMap.hs
+++ b/ClassyPrelude/HashMap.hs
@@ -17,7 +17,7 @@
 
 instance CanMapFunc (Map k v1) (Map k v2) v1 v2 where
     mapFunc = Map.map
-instance Hashable k => CanFilterFunc (Map k v) (k, v) where
+instance Hashable k => CanFilterFunc (Map k v) (Map k v) (k, v) where
     filterFunc = Map.filterWithKey . Prelude.curry
 instance CanLength (Map k v) Prelude.Int where
     length = Map.size
@@ -30,8 +30,6 @@
     unpack = Map.toList
 instance (Prelude.Eq k, Hashable k) => CanLookup (Map k v) k v where
     lookup = Map.lookup
-instance CanEmpty (Map k v) where
-    empty = Map.empty
 instance (Prelude.Eq k, Hashable k) => CanInsertVal (Map k v) k v where
     insertVal = Map.insert
 instance (Prelude.Eq k, Hashable k) => CanDelete (Map k v) k where
diff --git a/ClassyPrelude/HashSet.hs b/ClassyPrelude/HashSet.hs
--- a/ClassyPrelude/HashSet.hs
+++ b/ClassyPrelude/HashSet.hs
@@ -26,9 +26,10 @@
 instance (Hashable x, Eq x) => CanPack (Set x) x where
     pack = Set.fromList
     unpack = Set.toList
-instance CanEmpty (Set x) where
-    empty = Set.empty
 instance (Eq x, Hashable x, Set x ~ s, x ~ x') => CanInsert (x' -> s -> Set x) where
     insert = Set.insert
 instance (Eq x, Hashable x) => CanMember (Set x) x where
     member = Set.member
+
+instance CanFoldFunc (Set a) a accum where
+    foldFunc = Set.foldl'
diff --git a/ClassyPrelude/LByteString.hs b/ClassyPrelude/LByteString.hs
--- a/ClassyPrelude/LByteString.hs
+++ b/ClassyPrelude/LByteString.hs
@@ -17,11 +17,11 @@
 
 type LByteString = L.ByteString
 
-instance (co ~ LByteString, i ~ Word8, o ~ Word8) => CanMapFunc LByteString co i o where
+instance CanMapFunc LByteString LByteString Word8 Word8 where
     mapFunc = L.map
-instance (co ~ LByteString, i ~ Word8, o ~ LByteString) => CanConcatMapFunc LByteString co i o where
+instance CanConcatMapFunc LByteString LByteString Word8 LByteString where
     concatMapFunc = L.concatMap
-instance CanFilterFunc LByteString Word8 where
+instance CanFilterFunc LByteString LByteString Word8 where
     filterFunc = L.filter
 instance CanLength LByteString Int64 where
     length = L.length
@@ -32,8 +32,6 @@
 instance CanPack LByteString Word8 where
     pack = L.pack
     unpack = L.unpack
-instance CanEmpty LByteString where
-    empty = L.empty
 instance MonadIO m => CanReadFile (m LByteString) where
     readFile = liftIO . L.readFile . F.encodeString
 instance CanWriteFileFunc LByteString where
@@ -48,3 +46,12 @@
     all = L.all
 instance CanSplitAt LByteString Int64 where
     splitAt = L.splitAt
+
+instance CanReverse LByteString where
+    reverse = L.reverse
+
+instance CanFoldFunc LByteString Word8 accum where
+    foldFunc = L.foldl'
+
+instance CanReplicate LByteString Word8 Int64 where
+    replicate = L.replicate
diff --git a/ClassyPrelude/LHashMap.hs b/ClassyPrelude/LHashMap.hs
deleted file mode 100644
--- a/ClassyPrelude/LHashMap.hs
+++ /dev/null
@@ -1,38 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE FunctionalDependencies #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE TypeFamilies #-}
-module ClassyPrelude.LHashMap
-    ( LHashMap
-    ) where
-
-import qualified Prelude
-import Prelude ((.), Char)
-import ClassyPrelude.Classes
-import qualified Data.HashMap.Lazy as Map
-import Data.Hashable (Hashable)
-
-type LHashMap = Map.HashMap
-type Map = LHashMap
-
-instance CanMapFunc (Map k v1) (Map k v2) v1 v2 where
-    mapFunc = Map.map
-instance Hashable k => CanFilterFunc (Map k v) (k, v) where
-    filterFunc = Map.filterWithKey . Prelude.curry
-instance CanLength (Map k v) Prelude.Int where
-    length = Map.size
-instance (Prelude.Eq k, Hashable k, v' ~ v) => CanSingleton (v' -> Map k v) k where
-    singleton = Map.singleton
-instance CanNull (Map k v) where
-    null = Map.null
-instance (Prelude.Eq k, Hashable k) => CanPack (Map k v) (k, v) where
-    pack = Map.fromList
-    unpack = Map.toList
-instance (Prelude.Eq k, Hashable k) => CanLookup (Map k v) k v where
-    lookup = Map.lookup
-instance CanEmpty (Map k v) where
-    empty = Map.empty
-instance (Prelude.Eq k, Hashable k) => CanInsertVal (Map k v) k v where
-    insertVal = Map.insert
-instance (Prelude.Eq k, Hashable k) => CanDelete (Map k v) k where
-    delete = Map.delete
diff --git a/ClassyPrelude/LText.hs b/ClassyPrelude/LText.hs
--- a/ClassyPrelude/LText.hs
+++ b/ClassyPrelude/LText.hs
@@ -14,11 +14,11 @@
 
 type LText = TL.Text
 
-instance (co ~ LText, i ~ Char, o ~ Char) => CanMapFunc LText co i o where
+instance CanMapFunc LText LText Char Char where
     mapFunc = TL.map
-instance (co ~ LText, i ~ Char, o ~ LText) => CanConcatMapFunc LText co i o where
+instance CanConcatMapFunc LText LText Char LText where
     concatMapFunc = TL.concatMap
-instance CanFilterFunc LText Char where
+instance CanFilterFunc LText LText Char where
     filterFunc = TL.filter
 instance CanSingleton LText Prelude.Char where
     singleton = TL.singleton
@@ -27,10 +27,9 @@
 instance CanPack LText Prelude.Char where
     pack = TL.pack
     unpack = TL.unpack
-instance CanEmpty LText where
-    empty = TL.empty
 instance CanStripPrefix LText where
     stripPrefix = TL.stripPrefix
+    isPrefixOf = TL.isPrefixOf
 instance CanBreak LText Prelude.Char where
     break = TL.break
     span = TL.span
@@ -41,3 +40,31 @@
     all = TL.all
 instance CanSplitAt LText Int64 where
     splitAt = TL.splitAt
+
+instance CanWords LText where
+    words = TL.words
+    unwords = TL.unwords
+    lines = TL.lines
+    unlines = TL.unlines
+
+instance CanSplit LText Char where
+    split = TL.split
+
+instance CanStripSuffix LText where
+    stripSuffix = TL.stripSuffix
+    isSuffixOf = TL.isSuffixOf
+
+instance CanIsInfixOf LText where
+    isInfixOf = TL.isInfixOf
+
+instance CanReverse LText where
+    reverse = TL.reverse
+
+instance CanLength LText Int64 where
+    length = TL.length
+
+instance CanFoldFunc LText Char accum where
+    foldFunc = TL.foldl'
+
+instance CanReplicate LText LText Int64 where
+    replicate = TL.replicate
diff --git a/ClassyPrelude/List.hs b/ClassyPrelude/List.hs
--- a/ClassyPrelude/List.hs
+++ b/ClassyPrelude/List.hs
@@ -9,11 +9,11 @@
 import ClassyPrelude.Classes
 import qualified Data.List
 
-instance (i ~ a, co ~ [b]) => CanMapFunc [a] co i b where
+instance CanMapFunc [a] [b] a b where
     mapFunc = Prelude.map
-instance (i ~ a, co ~ [b]) => CanConcatMapFunc [a] co i [b] where
+instance CanConcatMapFunc [a] [b] a [b] where
     concatMapFunc = Prelude.concatMap
-instance CanFilterFunc [a] a where
+instance CanFilterFunc [a] [a] a where
     filterFunc = Prelude.filter
 instance CanLength [a] Prelude.Int where
     length = Prelude.length
@@ -24,14 +24,12 @@
 instance CanPack [a] a where
     pack = Prelude.id
     unpack = Prelude.id
-instance Prelude.Monad m => CanMapMFunc [a] [b] a b m where
+instance Prelude.Monad m => CanMapMFunc [i] (m [o]) m i o where
     mapMFunc = Prelude.mapM
-instance Prelude.Monad m => CanMapM_Func [a] a b m where
+instance CanMapM_Func [a] a where
     mapM_Func = Prelude.mapM_
 instance Prelude.Eq k => CanLookup [(k, v)] k v where
     lookup = Prelude.lookup
-instance CanEmpty [a] where
-    empty = []
 instance Prelude.Eq k => CanInsertVal [(k, v)] k v where
     insertVal k v c = (k, v) : delete k c
 instance Prelude.Eq k => CanDelete [(k, v)] k where
@@ -40,6 +38,7 @@
     member x = Prelude.any (Prelude.== x)
 instance Prelude.Eq a => CanStripPrefix [a] where
     stripPrefix = Data.List.stripPrefix
+    isPrefixOf = Data.List.isPrefixOf
 instance CanBreak [a] a where
     break = Prelude.break
     span = Prelude.span
@@ -50,5 +49,20 @@
     all = Prelude.all
 instance CanSplitAt [c] Prelude.Int where
     splitAt = Prelude.splitAt
-instance CanFoldFunc [a] accum a where
+instance CanFoldFunc [a] a accum where
     foldFunc = Data.List.foldl'
+
+instance (c ~ Prelude.Char) => CanWords [c] where
+    words = Prelude.words
+    unwords = Prelude.unwords
+    lines = Prelude.lines
+    unlines = Prelude.unlines
+
+instance Prelude.Eq a => CanIsInfixOf [a] where
+    isInfixOf = Data.List.isInfixOf
+
+instance CanReverse [a] where
+    reverse = Prelude.reverse
+
+instance CanReplicate [i] i Prelude.Int where
+    replicate = Prelude.replicate
diff --git a/ClassyPrelude/Map.hs b/ClassyPrelude/Map.hs
--- a/ClassyPrelude/Map.hs
+++ b/ClassyPrelude/Map.hs
@@ -14,7 +14,7 @@
 
 instance CanMapFunc (Map k v1) (Map k v2) v1 v2 where
     mapFunc = Map.map
-instance Prelude.Ord k => CanFilterFunc (Map k v) (k, v) where
+instance Prelude.Ord k => CanFilterFunc (Map k v) (Map k v) (k, v) where
     filterFunc = Map.filterWithKey . Prelude.curry
 instance CanLength (Map k v) Prelude.Int where
     length = Map.size
@@ -27,8 +27,6 @@
     unpack = Map.toList
 instance Prelude.Ord k => CanLookup (Map k v) k v where
     lookup = Map.lookup
-instance CanEmpty (Map k v) where
-    empty = Map.empty
 instance Prelude.Ord k => CanInsertVal (Map k v) k v where
     insertVal = Map.insert
 instance Prelude.Ord k => CanDelete (Map k v) k where
diff --git a/ClassyPrelude/Set.hs b/ClassyPrelude/Set.hs
--- a/ClassyPrelude/Set.hs
+++ b/ClassyPrelude/Set.hs
@@ -23,9 +23,10 @@
 instance Prelude.Ord x => CanPack (Set x) x where
     pack = Set.fromList
     unpack = Set.toList
-instance CanEmpty (Set x) where
-    empty = Set.empty
 instance (Prelude.Ord x, Set x ~ s, x ~ x') => CanInsert (x' -> s -> Set x) where
     insert = Set.insert
 instance Prelude.Ord x => CanMember (Set x) x where
     member = Set.member
+
+instance CanFoldFunc (Set a) a accum where
+    foldFunc = Set.foldl'
diff --git a/ClassyPrelude/Text.hs b/ClassyPrelude/Text.hs
--- a/ClassyPrelude/Text.hs
+++ b/ClassyPrelude/Text.hs
@@ -12,11 +12,11 @@
 import Data.Text (Text)
 import qualified Data.Text as T
 
-instance (co ~ Text, i ~ Char, o ~ Char) => CanMapFunc Text co i o where
+instance CanMapFunc Text Text Char Char where
     mapFunc = T.map
-instance (co ~ Text, i ~ Char, o ~ Text) => CanConcatMapFunc Text co i o where
+instance CanConcatMapFunc Text Text Char Text where
     concatMapFunc = T.concatMap
-instance CanFilterFunc Text Char where
+instance CanFilterFunc Text Text Char where
     filterFunc = T.filter
 instance CanLength Text Prelude.Int where
     length = T.length
@@ -27,10 +27,9 @@
 instance CanPack Text Prelude.Char where
     pack = T.pack
     unpack = T.unpack
-instance CanEmpty Text where
-    empty = T.empty
 instance CanStripPrefix Text where
     stripPrefix = T.stripPrefix
+    isPrefixOf = T.isPrefixOf
 instance CanBreak Text Prelude.Char where
     break = T.break
     span = T.span
@@ -41,3 +40,28 @@
     all = T.all
 instance CanSplitAt Text Prelude.Int where
     splitAt = T.splitAt
+
+instance CanWords Text where
+    words = T.words
+    unwords = T.unwords
+    lines = T.lines
+    unlines = T.unlines
+
+instance CanSplit Text Char where
+    split = T.split
+
+instance CanStripSuffix Text where
+    stripSuffix = T.stripSuffix
+    isSuffixOf = T.isSuffixOf
+
+instance CanIsInfixOf Text where
+    isInfixOf = T.isInfixOf
+
+instance CanReverse Text where
+    reverse = T.reverse
+
+instance CanFoldFunc Text Char accum where
+    foldFunc = T.foldl'
+
+instance CanReplicate Text Text Prelude.Int where
+    replicate = T.replicate
diff --git a/ClassyPrelude/Vector.hs b/ClassyPrelude/Vector.hs
--- a/ClassyPrelude/Vector.hs
+++ b/ClassyPrelude/Vector.hs
@@ -12,11 +12,11 @@
 import Data.Vector (Vector)
 import qualified Data.Vector as V
 
-instance (i ~ a, co ~ Vector b) => CanMapFunc (Vector a) co i b where
+instance CanMapFunc (Vector a) (Vector b) a b where
     mapFunc = V.map
-instance (i ~ a, co ~ Vector b) => CanConcatMapFunc (Vector a) co i (Vector b) where
+instance CanConcatMapFunc (Vector a) (Vector b) a (Vector b) where
     concatMapFunc = V.concatMap
-instance CanFilterFunc (Vector a) a where
+instance CanFilterFunc (Vector a) (Vector a) a where
     filterFunc = V.filter
 instance CanLength (Vector a) Prelude.Int where
     length = V.length
@@ -27,12 +27,10 @@
 instance CanPack (Vector a) a where
     pack = V.fromList
     unpack = V.toList
-instance Prelude.Monad m => CanMapMFunc (Vector a) (Vector b) a b m where
+instance Prelude.Monad m => CanMapMFunc (Vector i) (m (Vector o)) m i o where
     mapMFunc = V.mapM
-instance Prelude.Monad m => CanMapM_Func (Vector a) a b m where
+instance CanMapM_Func (Vector a) a where
     mapM_Func = V.mapM_
-instance CanEmpty (Vector a) where
-    empty = V.empty
 instance Prelude.Eq x => CanMember (Vector x) x where
     member x = V.any (Prelude.== x)
 instance CanBreak (Vector a) a where
@@ -45,5 +43,11 @@
     all = V.all
 instance CanSplitAt (Vector a) Prelude.Int where
     splitAt = V.splitAt
-instance CanFoldFunc (Vector a) accum a where
+instance CanFoldFunc (Vector a) a accum where
     foldFunc = V.foldl'
+
+instance CanReverse (Vector a) where
+    reverse = V.reverse
+
+instance CanReplicate (Vector a) a Prelude.Int where
+    replicate = V.replicate
diff --git a/classy-prelude.cabal b/classy-prelude.cabal
--- a/classy-prelude.cabal
+++ b/classy-prelude.cabal
@@ -1,5 +1,5 @@
 name:                classy-prelude
-version:             0.1.0.0
+version:             0.2.0.0
 synopsis:            A typeclass-based Prelude.
 description:         Focuses on using common typeclasses when possible, and creating new ones to avoid name clashing. Exposes many recommended datastructures (Map, ByteString, etc) directly without requiring long import lists and qualified modules.
 homepage:            https://github.com/snoyberg/classy-prelude
@@ -24,9 +24,9 @@
                        ClassyPrelude.FilePath
                        ClassyPrelude.Vector
                        ClassyPrelude.HashMap
-                       ClassyPrelude.LHashMap
                        ClassyPrelude.HashSet
   build-depends:       base                          >= 4          && < 5
+                     , basic-prelude                 >= 0.2        && < 0.3
                      , system-filepath               >= 0.4        && < 0.5
                      , transformers
                      , containers
@@ -36,3 +36,18 @@
                      , unordered-containers
                      , hashable
   ghc-options:         -Wall -fno-warn-orphans
+
+test-suite test
+    hs-source-dirs: test
+    main-is: main.hs
+    type: exitcode-stdio-1.0
+    build-depends:   classy-prelude
+                   , base
+                   , hspec == 1.3.*
+                   , QuickCheck
+                   , transformers
+    ghc-options:     -Wall
+
+source-repository head
+  type:     git
+  location: git://github.com/snoyberg/classy-prelude.git
diff --git a/test/main.hs b/test/main.hs
new file mode 100644
--- /dev/null
+++ b/test/main.hs
@@ -0,0 +1,251 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoMonomorphismRestriction #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+import Test.Hspec
+import Test.Hspec.QuickCheck
+import ClassyPrelude
+import ClassyPrelude.Classes
+import Test.QuickCheck.Arbitrary
+import Prelude (asTypeOf, undefined, fromIntegral)
+import qualified Prelude
+import Control.Monad.Trans.Writer (tell, Writer, runWriter)
+
+dictionaryProps
+    :: ( CanInsertVal a Int Char
+       , CanDelete a Int
+       , Show a
+       , Eq a
+       , Arbitrary a
+       , Monoid a
+       , CanLookup a Int Char
+       )
+    => a -> Spec
+dictionaryProps dummy = do
+    prop "insert x y (insert x z c) == insert x y c" $ \x y z c ->
+        insert x y (insert x z (c `asTypeOf` dummy)) == insert x y c
+    prop "insert x y (delete x c) == insert x y c" $ \x y c ->
+        insert x y (delete x (c `asTypeOf` dummy)) == insert x y c
+    prop "delete x (insert x y c) == delete x c" $ \x y c ->
+        delete x (insert x y (c `asTypeOf` dummy)) == delete x c
+    prop "lookup k (insert k v empty) == Just v" $ \k v ->
+        lookup k (insert k v empty `asTypeOf` dummy) == Just v
+    prop "lookup k (delete k c) == Nothing" $ \k c ->
+        lookup k (delete k c`asTypeOf` dummy) == Nothing
+
+mapProps :: ( CanPack a i
+            , CanPack b j
+            , Eq a
+            , Eq c
+            , Show a
+            , Arbitrary a
+            , Eq b
+            , Show b
+            , Arbitrary b
+            , CanMapFunc a b i j
+            , CanMapFunc a c i k
+            , CanMapFunc b c j k
+            )
+         => a
+         -> (i -> j)
+         -> (j -> k)
+         -> Spec
+mapProps dummy f g = do
+    prop "map f c == pack (map f (unpack c))" $ \c ->
+        map f (c `asTypeOf` dummy) == pack (map f (unpack c))
+    prop "map (f . g) c == map f (map g c)" $ \c ->
+        map (g . f) (c `asTypeOf` dummy) == map g (map f c)
+
+concatMapProps :: ( CanPack a i
+            , CanPack b j
+            , CanPack js j
+            , Eq a
+            , Show a
+            , Arbitrary a
+            , Eq b
+            , Show b
+            , Arbitrary b
+            , CanMapFunc a b i j
+            , CanConcatMapFunc a b i js
+            )
+         => a
+         -> (i -> js)
+         -> Spec
+concatMapProps dummy f = do
+    prop "concatMap f c == pack (concatMap (unpack . f) (unpack c))" $ \c ->
+        concatMap f (c `asTypeOf` dummy) == pack (concatMap (unpack . f) (unpack c))
+
+filterProps :: ( CanPack a i
+               , Show a
+               , Arbitrary a
+               , Eq a
+               , CanFilterFunc a a i
+               )
+            => a
+            -> (i -> Bool)
+            -> Spec
+filterProps dummy f = do
+    prop "filter f c == pack (filter f (unpack c))" $ \c ->
+        filter f (c `asTypeOf` dummy) == pack (filter f (unpack c))
+
+lengthProps :: ( Show a
+               , Eq a
+               , Arbitrary a
+               , CanPack a i
+               , CanLength a len
+               , Prelude.Num len
+               , Eq len
+               , CanNull a
+               , Ord len
+               , Monoid a
+               )
+            => a -> Spec
+lengthProps dummy = do
+    prop "length c == fromIntegral (length (unpack c))" $ \c ->
+        length (c `asTypeOf` dummy) == fromIntegral (length (unpack c))
+    prop "null c == (length c == 0)" $ \c ->
+        null (c `asTypeOf` dummy) == (length c == 0)
+    prop "length (x ++ y) <= length x + length y" $ \x y ->
+        length (x ++ y `asTypeOf` dummy) <= length x + length y
+    prop "length (x ++ y) >= max (length x) (length y)" $ \x y ->
+        length (x ++ y `asTypeOf` dummy) >= max (length x) (length y)
+    prop "length (x ++ empty) == length x" $ \x ->
+        length (x ++ empty `asTypeOf` dummy) == length x
+    prop "null empty" $ null (empty `asTypeOf` dummy)
+
+{-
+mapMProps :: ( Show a
+             , Arbitrary a
+             , CanPack a i
+             , Eq i
+             , CanMapMFunc a co i i
+             , CanPack co i
+             , Eq co
+             )
+           => a -> Spec
+-}
+mapMProps dummy = do
+    let f :: Int -> Writer [Int] Int
+        f x = tell [x] >> return x
+    prop "mapM_ f c == mapM_ f (toList c)" $ \c ->
+        runWriter (mapM f (c `asTypeOf` dummy)) ==
+            let (x, y) = runWriter (mapM f (toList c))
+             in (pack x, y)
+
+mapM_Props :: ( Show a
+              , Arbitrary a
+              , CanPack a i
+              , Eq i
+              , CanMapM_Func a i
+              )
+           => a -> Spec
+mapM_Props dummy = do
+    let f x = tell [x]
+    prop "mapM_ f c == mapM_ f (toList c)" $ \c ->
+        runWriter (mapM_ f (c `asTypeOf` dummy)) == runWriter (mapM_ f (toList c))
+
+foldProps dummy f accum =
+    prop "fold f accum c == fold f accum (toList c)" $ \c ->
+        fold f accum (c `asTypeOf` dummy) == fold f accum (toList c)
+
+replicateProps :: ( Show a
+                  , Eq a
+                  , CanReplicate a i len
+                  , Integral len
+                  , Show len
+                  , Arbitrary len
+                  , Show i
+                  , Arbitrary i
+                  )
+               => a -> ([i] -> a) -> Spec
+replicateProps dummy pack' =
+    prop "replicate i a == pack (replicate i a)" $ \{- takes too long i-} a ->
+        (replicate i a `asTypeOf` dummy) == pack' (replicate (fromIntegral i) a)
+  where
+    i = 3
+
+main :: IO ()
+main = hspec $ do
+    describe "dictionary" $ do
+        describe "Data.Map" $ dictionaryProps (undefined :: Map Int Char)
+        describe "Data.HashMap" $ dictionaryProps (undefined :: HashMap Int Char)
+        describe "assoc list" $ dictionaryProps (undefined :: [(Int, Char)])
+    describe "map" $ do
+        describe "list" $ mapProps (undefined :: [Int]) (+ 1) (+ 2)
+        describe "Data.Vector" $ mapProps (undefined :: Vector Int) (+ 1) (+ 2)
+        describe "Data.Set" $ mapProps (undefined :: Set Int) (+ 1) (+ 2)
+        describe "Data.HashSet" $ mapProps (undefined :: HashSet Int) (+ 1) (+ 2)
+        describe "Data.ByteString" $ mapProps (undefined :: ByteString) (+ 1) (+ 2)
+        describe "Data.ByteString.Lazy" $ mapProps (undefined :: LByteString) (+ 1) (+ 2)
+        describe "Data.Text" $ mapProps (undefined :: Text) succ succ
+        describe "Data.Text.Lazy" $ mapProps (undefined :: LText) succ succ
+    describe "concatMap" $ do
+        describe "list" $ concatMapProps (undefined :: [Int]) (\i -> [i + 1, i + 2])
+        describe "Data.Vector" $ concatMapProps (undefined :: Vector Int) (\i -> fromList [i + 1, i + 2])
+        describe "Data.ByteString" $ concatMapProps (undefined :: ByteString) (\i -> fromList [i + 1, i + 2])
+        describe "Data.ByteString.Lazy" $ concatMapProps (undefined :: LByteString) (\i -> fromList [i + 1, i + 2])
+        describe "Data.Text" $ concatMapProps (undefined :: Text) (\c -> pack [succ c, succ $ succ c])
+        describe "Data.Text.Lazy" $ concatMapProps (undefined :: LText) (\c -> pack [succ c, succ $ succ c])
+    describe "filter" $ do
+        describe "list" $ filterProps (undefined :: [Int]) (< 20)
+        describe "Data.Vector" $ filterProps (undefined :: Vector Int) (< 20)
+        describe "Data.ByteString" $ filterProps (undefined :: ByteString) (< 20)
+        describe "Data.ByteString.Lazy" $ filterProps (undefined :: LByteString) (< 20)
+        describe "Data.Text" $ filterProps (undefined :: Text) (< 'A')
+        describe "Data.Text.Lazy" $ filterProps (undefined :: LText) (< 'A')
+        describe "Data.Map" $ filterProps (undefined :: Map Int Char) (\(i, _) -> i < 20)
+        describe "Data.HashMap" $ filterProps (undefined :: HashMap Int Char) (\(i, _) -> i < 20)
+    describe "length" $ do
+        describe "list" $ lengthProps (undefined :: [Int])
+        describe "Data.Vector" $ lengthProps (undefined :: Vector Int)
+        describe "Data.ByteString" $ lengthProps (undefined :: ByteString)
+        describe "Data.ByteString.Lazy" $ lengthProps (undefined :: LByteString)
+        describe "Data.Text" $ lengthProps (undefined :: Text)
+        describe "Data.Text.Lazy" $ lengthProps (undefined :: LText)
+        describe "Data.Map" $ lengthProps (undefined :: Map Int Char)
+        describe "Data.HashMap" $ lengthProps (undefined :: HashMap Int Char)
+        describe "Data.Set" $ lengthProps (undefined :: Set Int)
+        describe "Data.HashSet" $ lengthProps (undefined :: HashSet Int)
+    describe "mapM" $ do
+        describe "list" $ mapMProps (undefined :: [Int])
+        describe "Data.Vector" $ mapMProps (undefined :: Vector Int)
+    describe "mapM_" $ do
+        describe "list" $ mapM_Props (undefined :: [Int])
+        describe "Data.Vector" $ mapM_Props (undefined :: Vector Int)
+    describe "fold" $ do
+        let f = flip (:)
+        describe "list" $ foldProps (undefined :: [Int]) f []
+        describe "Data.Vector" $ foldProps (undefined :: Vector Int) f []
+        describe "Data.ByteString" $ foldProps (undefined :: ByteString) f []
+        describe "Data.ByteString.Lazy" $ foldProps (undefined :: LByteString) f []
+        describe "Data.Text" $ foldProps (undefined :: Text) f []
+        describe "Data.Text.Lazy" $ foldProps (undefined :: LText) f []
+        describe "Data.Set" $ foldProps (undefined :: Set Int) f []
+        describe "Data.HashSet" $ foldProps (undefined :: HashSet Int) f []
+    describe "replicate" $ do
+        describe "list" $ replicateProps (undefined :: [Int]) pack
+        describe "Data.Vector" $ replicateProps (undefined :: Vector Int) pack
+        describe "Data.ByteString" $ replicateProps (undefined :: ByteString) pack
+        describe "Data.ByteString.Lazy" $ replicateProps (undefined :: LByteString) pack
+        describe "Data.Text" $ replicateProps (undefined :: Text) concat
+        describe "Data.Text.Lazy" $ replicateProps (undefined :: LText) concat
+
+instance Arbitrary (Map Int Char) where
+    arbitrary = fromList <$> arbitrary
+instance Arbitrary (HashMap Int Char) where
+    arbitrary = fromList <$> arbitrary
+instance Arbitrary (Vector Int) where
+    arbitrary = fromList <$> arbitrary
+instance Arbitrary (Set Int) where
+    arbitrary = fromList <$> arbitrary
+instance Arbitrary (HashSet Int) where
+    arbitrary = fromList <$> arbitrary
+instance Arbitrary ByteString where
+    arbitrary = fromList <$> arbitrary
+instance Arbitrary LByteString where
+    arbitrary = fromList <$> arbitrary
+instance Arbitrary Text where
+    arbitrary = fromList <$> arbitrary
+instance Arbitrary LText where
+    arbitrary = fromList <$> arbitrary
