diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2010, Byron James Johnson
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+
+2. 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.
+
+3. Neither the name of the author nor the names of its 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.
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/src/Data/String/Class.hs b/src/Data/String/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/String/Class.hs
@@ -0,0 +1,788 @@
+{-# LANGUAGE TypeFamilies, FlexibleContexts, TypeSynonymInstances, ExistentialQuantification, DeriveDataTypeable #-}
+
+module Data.String.Class
+    ( StringCells(..)
+    , StringCell(..)
+    , ConvGenString(..)
+    , ConvString(..)
+    , ConvStrictByteString(..)
+    , ConvLazyByteString(..)
+    , ConvText(..)
+    , GenString(..)
+    , GenStringDefault
+    ) where
+
+import Prelude hiding (head, tail, last, init, take, drop, length, null, concat)
+import Control.Applicative hiding (empty)
+import qualified Data.ByteString as S
+import qualified Data.ByteString.Char8 as SC
+import qualified Data.ByteString.Internal as BI
+import qualified Data.ByteString.Lazy as L
+import qualified Data.ByteString.Lazy.Char8 as LC
+import Data.Int
+import qualified Data.List as List
+import Data.Tagged
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as TE
+import qualified Data.Text.Encoding.Error as TEE
+import Data.Typeable
+import Data.Word
+
+-- | Minimal complete definition: StringCellChar; StringCellAltChar; toStringCells; fromStringCells; toMainChar; toAltChar; cons; snoc; either all of head, tail, last, and init, or all of uncons and unsnoc; take, take64 or genericTake; drop, drop64, or genericDrop; length, length64, or genericLength; empty; null; and concat
+class (StringCell (StringCellChar s), StringCell (StringCellAltChar s), ConvGenString s, ConvString s, ConvStrictByteString s, ConvLazyByteString s, ConvText s, Eq s, Typeable s) => StringCells s where
+    type StringCellChar s
+    type StringCellAltChar s
+
+    toStringCells   :: (StringCells s2) => s  -> s2
+    fromStringCells :: (StringCells s2) => s2 -> s
+
+    infixr 9 `cons`
+    infixr 9 `uncons`
+    infixr 9 `altCons`
+    infixr 9 `altUncons`
+    cons      :: StringCellChar s -> s -> s
+    uncons    :: s -> (StringCellChar s, s)
+    snoc      :: s -> StringCellChar s -> s
+    unsnoc    :: s -> (s, StringCellChar s)
+    altCons   :: StringCellAltChar s -> s -> s
+    altUncons :: s -> (StringCellAltChar s, s)
+    altSnoc   :: s -> StringCellAltChar s -> s
+    altUnsnoc :: s -> (s, StringCellAltChar s)
+
+    toMainChar :: (StringCell c) => c -> Tagged s (StringCellChar s)
+    toAltChar  :: (StringCell c) => c -> Tagged s (StringCellAltChar s)
+
+    -- | Append two strings
+    infixr 9 `append`
+    append :: s -> s -> s
+    concat :: [s] -> s
+
+    empty :: s
+    null :: s -> Bool
+
+    head :: s -> StringCellChar s
+    tail :: s -> s
+    last :: s -> StringCellChar s
+    init :: s -> s
+    altHead :: s -> StringCellAltChar s
+    altLast :: s -> StringCellAltChar s
+
+    -- | Construction of a string; implementations should behave safely with incorrect lengths
+    --
+    -- The default implementation of 'undfoldr' is independent from that of 'altUnfoldr',
+    -- as well as 'unfoldrN' as and 'altUnfoldrN'.
+    unfoldr     ::        (a -> Maybe (StringCellChar    s, a)) -> a -> s
+    altUnfoldr  ::        (a -> Maybe (StringCellAltChar s, a)) -> a -> s
+    unfoldrN    :: Int -> (a -> Maybe (StringCellChar    s, a)) -> a -> s
+    altUnfoldrN :: Int -> (a -> Maybe (StringCellAltChar s, a)) -> a -> s
+
+    unfoldr f b =
+        case f b of
+            (Just (a, new_b)) -> a `cons` unfoldr f new_b
+            (Nothing)         -> empty
+
+    altUnfoldr f b =
+        case f b of
+            (Just (a, new_b)) -> a `altCons` altUnfoldr f new_b
+            (Nothing)         -> empty
+    unfoldrN    = const unfoldr
+    altUnfoldrN = const altUnfoldr
+
+    -- | Get the character at the given position
+    --
+    -- Just like 'drop', 'drop64', and the variants of those functions, the
+    -- default definitions of these three variants are independent of each
+    -- other, and are defined in terms of 'head' and 'tail', which can be
+    -- inefficient.
+    index   :: s -> Int   -> StringCellChar s
+    index64 :: s -> Int64 -> StringCellChar s
+    -- | Index a string at any location
+    --
+    -- Just like the other 'generic' functions of this module, this function
+    -- can be significantly slower than 'index', since the function must be
+    -- able to support arbitrarily large indices.  Consider using 'index' or
+    -- 'index64', even if you need to coerce the index to an 'Int'.
+    genericIndex :: (Integral i) => s -> i -> StringCellChar s
+
+    take        :: Int -> s -> s
+    take64      :: Int64 -> s -> s
+    genericTake :: (Integral i) => i -> s -> s
+    drop        :: Int -> s -> s
+    drop64      :: Int64 -> s -> s
+    genericDrop :: (Integral i) => i -> s -> s
+
+    length        :: s -> Int
+    length64      :: s -> Int64
+    genericLength :: (Integral i) => s -> i
+
+    safeUncons        :: s -> Maybe ((StringCellChar s), s)
+    safeUnsnoc        :: s -> Maybe (s, (StringCellChar s))
+    safeAltUncons     :: s -> Maybe ((StringCellAltChar s), s)
+    safeAltUnsnoc     :: s -> Maybe (s, (StringCellAltChar s))
+    safeHead          :: s -> Maybe (StringCellChar s)
+    safeTail          :: s -> Maybe s
+    safeLast          :: s -> Maybe (StringCellChar s)
+    safeInit          :: s -> Maybe s
+    safeAltHead       :: s -> Maybe (StringCellAltChar s)
+    safeAltLast       :: s -> Maybe (StringCellAltChar s)
+    safeIndex         :: s -> Int   -> Maybe (StringCellChar s)
+    safeIndex64       :: s -> Int64 -> Maybe (StringCellChar s)
+    safeGenericIndex  :: (Integral i) => s -> i -> Maybe (StringCellChar s)
+    safeTake          :: Int -> s -> Maybe s
+    safeTake64        :: Int64 -> s -> Maybe s
+    safeGenericTake   :: (Integral i) => i -> s -> Maybe s
+    safeDrop          :: Int -> s -> Maybe s
+    safeDrop64        :: Int64 -> s -> Maybe s
+    safeGenericDrop   :: (Integral i) => i -> s -> Maybe s
+    safeUncons2       :: s -> Maybe ((StringCellChar s), (StringCellChar s), s)
+    safeUncons3       :: s -> Maybe ((StringCellChar s), (StringCellChar s), (StringCellChar s), s)
+    safeUncons4       :: s -> Maybe ((StringCellChar s), (StringCellChar s), (StringCellChar s), (StringCellChar s), s)
+
+    infixr 9 `cons2`
+    infixr 9 `cons3`
+    infixr 9 `cons4`
+    infixr 9 `uncons2`
+    infixr 9 `uncons3`
+    infixr 9 `uncons4`
+    cons2   :: StringCellChar s -> StringCellChar s -> s -> s
+    cons3   :: StringCellChar s -> StringCellChar s -> StringCellChar s -> s -> s
+    cons4   :: StringCellChar s -> StringCellChar s -> StringCellChar s -> StringCellChar s -> s -> s
+    uncons2 :: s -> (StringCellChar s, StringCellChar s, s)
+    uncons3 :: s -> (StringCellChar s, StringCellChar s, StringCellChar s, s)
+    uncons4 :: s -> (StringCellChar s, StringCellChar s, StringCellChar s, StringCellChar s, s)
+
+    altCons c s = cons (s `untagTypeOf` toMainChar c) s
+    altSnoc s c = snoc s (s `untagTypeOf` toMainChar c)
+    altUncons s = (\ ~(a, s') -> (s `untagTypeOf` toAltChar a, s')) $ uncons s
+    altUnsnoc s = (\ ~(s', a) -> (s', s `untagTypeOf` toAltChar a)) $ unsnoc s
+
+    head = fst . uncons
+    tail = snd . uncons
+    last = snd . unsnoc
+    init = fst . unsnoc
+    altHead s = (s `untagTypeOf`) . toAltChar . head $ s
+    altLast s = (s `untagTypeOf`) . toAltChar . last $ s
+
+    index        s 0 = head s
+    index        s n = (flip index $ pred n) . tail $ s
+    index64      s 0 = head s
+    index64      s n = (flip index64 $ pred n) . tail $ s
+    genericIndex s 0 = head s
+    genericIndex s n = (flip genericIndex $ pred n) . tail $ s
+
+    take        n s = take64      (fromIntegral n) s
+    take64      n s = genericTake (fromIntegral n  :: Integer) s
+    genericTake n s = take        (fromIntegral n) s
+    drop        n s = drop64      (fromIntegral n) s
+    drop64      n s = genericDrop (fromIntegral n  :: Integer) s
+    genericDrop n s = drop        (fromIntegral n) s
+
+    length        = fromIntegral . length64
+    length64      = (fromIntegral :: Integer -> Int64) . genericLength
+    genericLength = fromIntegral . length
+
+    append a b = case safeUncons a of
+        (Just (c, cs)) -> c `cons` append cs b
+        (Nothing)      -> a
+
+    concat = foldr append empty
+
+    uncons s = (head s, tail s)
+    unsnoc s = (init s, last s)
+
+    cons2 a b s = a `cons` b `cons` s
+    cons3 a b c s = a `cons` b `cons` c `cons` s
+    cons4 a b c d s = a `cons` b `cons` c `cons` d `cons` s
+    uncons2 s       =
+        let (a, s')   = uncons s
+            (b, s'')  = uncons s'
+        in  (a, b, s'')
+    uncons3 s       =
+        let (a, s')   = uncons s
+            (b, s'')  = uncons s'
+            (c, s''') = uncons s''
+        in  (a, b, c, s''')
+    uncons4 s       =
+        let (a, s')    = uncons s
+            (b, s'')   = uncons s'
+            (c, s''')  = uncons s''
+            (d, s'''') = uncons s'''
+        in  (a, b, c, d, s'''')
+
+    safeUncons s
+        | null s    = Nothing
+        | otherwise = Just $ uncons s
+    safeUnsnoc s
+        | null s    = Nothing
+        | otherwise = Just $ unsnoc s
+    safeAltUncons s
+        | null s    = Nothing
+        | otherwise = Just $ altUncons s
+    safeAltUnsnoc s
+        | null s    = Nothing
+        | otherwise = Just $ altUnsnoc s
+    safeHead s
+        | null s    = Nothing
+        | otherwise = Just $ head s
+    safeTail s
+        | null s    = Nothing
+        | otherwise = Just $ tail s
+    safeLast s
+        | null s    = Nothing
+        | otherwise = Just $ last s
+    safeInit s
+        | null s    = Nothing
+        | otherwise = Just $ init s
+    safeAltHead s
+        | null s    = Nothing
+        | otherwise = Just $ altHead s
+    safeAltLast s
+        | null s    = Nothing
+        | otherwise = Just $ altLast s
+    safeIndex s n
+        | length s <= n = Nothing
+        | otherwise     = Just $ s `index` n
+    safeIndex64 s n
+        | length64 s <= n = Nothing
+        | otherwise     = Just $ s `index64` n
+    safeGenericIndex s n
+        | genericLength s <= n = Nothing
+        | otherwise            = Just $ s `genericIndex` n
+    safeTake n s
+        | n > length s = Nothing
+        | otherwise    = Just $ take n s
+    safeTake64 n s
+        | n > length64 s = Nothing
+        | otherwise      = Just $ take64 n s
+    safeGenericTake n s
+        | n > genericLength s = Nothing
+        | otherwise           = Just $ genericTake n s
+    safeDrop n s
+        | n > length s = Nothing
+        | otherwise    = Just $ drop n s
+    safeDrop64 n s
+        | n > length64 s = Nothing
+        | otherwise      = Just $ drop64 n s
+    safeGenericDrop n s
+        | n > genericLength s = Nothing
+        | otherwise           = Just $ genericDrop n s
+    safeUncons2 s = do
+        (a, s')    <- safeUncons s
+        (b, s'')   <- safeUncons s'
+        return (a, b, s'')
+    safeUncons3 s = do
+        (a, s')    <- safeUncons s
+        (b, s'')   <- safeUncons s'
+        (c, s''')  <- safeUncons s''
+        return (a, b, c, s''')
+    safeUncons4 s = do
+        (a, s')    <- safeUncons s
+        (b, s'')   <- safeUncons s'
+        (c, s''')  <- safeUncons s''
+        (d, s'''') <- safeUncons s'''
+        return (a, b, c, d, s'''')
+
+class StringCell c where
+    toChar     :: c      -> Char
+    toWord8    :: c      -> Word8
+    toWord16   :: c      -> Word16
+    toWord32   :: c      -> Word32
+    toWord64   :: c      -> Word64
+    fromChar   :: Char   -> c
+    fromWord8  :: Word8  -> c
+    fromWord16 :: Word16 -> c
+    fromWord32 :: Word32 -> c
+    fromWord64 :: Word64 -> c
+
+class ConvGenString s where
+    toGenString   :: s -> GenString
+    fromGenString :: GenString -> s
+
+class ConvString s where
+    toString   :: s -> String
+    fromString :: String -> s
+
+class ConvStrictByteString s where
+    toStrictByteString :: s -> S.ByteString
+    fromStrictByteString :: S.ByteString -> s
+
+class ConvLazyByteString s where
+    toLazyByteString :: s -> L.ByteString
+    fromLazyByteString :: L.ByteString -> s
+
+class ConvText s where
+    toText :: s -> T.Text
+    fromText :: T.Text -> s
+
+
+
+instance StringCells String where
+    type StringCellChar    String = Char
+    type StringCellAltChar String = Char
+
+    toStringCells   = fromString
+    fromStringCells = toString
+
+    length = List.genericLength
+    empty  = []
+    null   = List.null
+    cons          = (:)
+    snoc s c      = s ++ [c]
+    safeUncons (x:xs) = Just (x, xs)
+    safeUncons _      = Nothing
+    uncons (x:xs) = (x, xs)
+    uncons _      = error "String.uncons: null string"
+    toMainChar    = Tagged . toChar
+    toAltChar     = Tagged . toChar
+    head          = List.head
+    tail          = List.tail
+    init          = List.init
+    last          = List.last
+    unfoldr       = List.unfoldr
+    index         = (List.!!)
+    index64 s     = index s . fromIntegral
+    genericIndex  = List.genericIndex
+    take          = List.take
+    genericTake   = List.genericTake
+    drop          = List.drop
+    genericDrop   = List.genericDrop
+    append        = (List.++)
+    concat        = List.concat
+
+instance StringCells S.ByteString where
+    type StringCellChar    S.ByteString = Word8
+    type StringCellAltChar S.ByteString = Char
+
+    toStringCells   = fromStrictByteString
+    fromStringCells = toStrictByteString
+
+    length          = S.length
+    empty           = S.empty
+    null            = S.null
+    cons            = S.cons
+    snoc            = S.snoc
+    safeUncons      = S.uncons
+    uncons          = maybe (error "StringCells.Data.ByteString.ByteString.uncons: string is null") id . safeUncons
+    toMainChar      = Tagged . toWord8
+    toAltChar       = Tagged . toChar
+    head            = S.head
+    tail            = S.tail
+    init            = S.init
+    last            = S.last
+    unfoldr         = S.unfoldr
+    altUnfoldr      = SC.unfoldr
+    unfoldrN        = ((fst .) .) . S.unfoldrN
+    altUnfoldrN     = ((fst .) .) . SC.unfoldrN
+    index           = S.index
+    index64 s       = index s . fromIntegral
+    take            = S.take
+    drop            = S.drop
+    append          = S.append
+    concat          = S.concat
+
+instance StringCells L.ByteString where
+    type StringCellChar    L.ByteString = Word8
+    type StringCellAltChar L.ByteString = Char
+
+    toStringCells   = fromLazyByteString
+    fromStringCells = toLazyByteString
+
+    length64        = L.length
+    length          = fromIntegral . length64
+    empty           = L.empty
+    null            = L.null
+    cons            = L.cons
+    snoc            = L.snoc
+    safeUncons      = L.uncons
+    uncons          = maybe (error "StringCells.Data.ByteString.Lazy.ByteString.uncons: string is null") id . safeUncons
+    toMainChar      = Tagged . toWord8
+    toAltChar       = Tagged . toChar
+    head            = L.head
+    tail            = L.tail
+    init            = L.init
+    last            = L.last
+    unfoldr         = L.unfoldr
+    altUnfoldr      = LC.unfoldr
+    index s         = index64 s . fromIntegral
+    index64         = L.index
+    take64          = L.take
+    drop64          = L.drop
+    append          = L.append
+    concat          = L.concat
+
+instance StringCells T.Text where
+    type StringCellChar    T.Text = Char
+    type StringCellAltChar T.Text = Char
+
+    toStringCells   = fromText
+    fromStringCells = toText
+
+    length          = T.length
+    empty           = T.empty
+    null            = T.null
+    cons            = T.cons
+    safeUncons      = T.uncons
+    uncons          = maybe (error "StringCells.Data.Text.Text.uncons: string is null") id . safeUncons
+    snoc            = T.snoc
+    altSnoc         = T.snoc
+    toMainChar      = Tagged . toChar
+    toAltChar       = Tagged . toChar
+    head            = T.head
+    tail            = T.tail
+    init            = T.init
+    last            = T.last
+    unfoldr         = T.unfoldr
+    altUnfoldr      = T.unfoldr
+    unfoldrN        = T.unfoldrN
+    altUnfoldrN     = T.unfoldrN
+    index           = T.index
+    index64 s       = index s . fromIntegral
+    append          = T.append
+    concat          = T.concat
+
+instance StringCell Char where
+    toChar     = id
+    toWord8    = BI.c2w
+    toWord16   = fromIntegral . toWord8
+    toWord32   = fromIntegral . toWord8
+    toWord64   = fromIntegral . toWord8
+    fromChar   = id
+    fromWord8  = BI.w2c
+    fromWord16 = BI.w2c . fromIntegral
+    fromWord32 = BI.w2c . fromIntegral
+    fromWord64 = BI.w2c . fromIntegral
+
+instance StringCell Word8 where
+    toChar     = BI.w2c
+    toWord8    = id
+    toWord16   = fromIntegral
+    toWord32   = fromIntegral
+    toWord64   = fromIntegral
+    fromChar   = BI.c2w
+    fromWord8  = id
+    fromWord16 = fromIntegral
+    fromWord32 = fromIntegral
+    fromWord64 = fromIntegral
+
+instance StringCell Word16 where
+    toChar     = BI.w2c . fromIntegral
+    toWord8    = fromIntegral
+    toWord16   = id
+    toWord32   = fromIntegral
+    toWord64   = fromIntegral
+    fromChar   = fromIntegral . BI.c2w
+    fromWord8  = fromIntegral
+    fromWord16 = id
+    fromWord32 = fromIntegral
+    fromWord64 = fromIntegral
+
+instance StringCell Word32 where
+    toChar     = BI.w2c . fromIntegral
+    toWord8    = fromIntegral
+    toWord16   = fromIntegral
+    toWord32   = id
+    toWord64   = fromIntegral
+    fromChar   = fromIntegral . BI.c2w
+    fromWord8  = fromIntegral
+    fromWord16 = fromIntegral
+    fromWord32 = id
+    fromWord64 = fromIntegral
+
+instance StringCell Word64 where
+    toChar     = BI.w2c . fromIntegral
+    toWord8    = fromIntegral
+    toWord16   = fromIntegral
+    toWord32   = fromIntegral
+    toWord64   = id
+    fromChar   = fromIntegral . BI.c2w
+    fromWord8  = fromIntegral
+    fromWord16 = fromIntegral
+    fromWord32 = fromIntegral
+    fromWord64 = id
+
+instance ConvGenString GenString where
+    toGenString   = id
+    fromGenString = id
+
+instance ConvGenString String where
+    toGenString      = GenString
+    fromGenString _s = case _s of
+        (GenString _s) -> toStringCells _s
+
+instance ConvGenString SC.ByteString where
+    toGenString      = GenString
+    fromGenString _s = case _s of
+        (GenString _s) -> toStringCells _s
+
+instance ConvGenString LC.ByteString where
+    toGenString      = GenString
+    fromGenString _s = case _s of
+        (GenString _s) -> toStringCells _s
+
+instance ConvGenString T.Text where
+    toGenString      = GenString
+    fromGenString _s = case _s of
+        (GenString _s) -> toStringCells _s
+
+instance ConvString GenString where
+    toString   = fromGenString
+    fromString = toGenString
+
+instance ConvString String where
+    toString   = id
+    fromString = id
+
+instance ConvString SC.ByteString where
+    toString   = SC.unpack
+    fromString = SC.pack
+
+instance ConvString LC.ByteString where
+    toString   = LC.unpack
+    fromString = LC.pack
+
+instance ConvString T.Text where
+    toString   = T.unpack
+    fromString = T.pack
+
+instance ConvStrictByteString GenString where
+    toStrictByteString   = fromGenString
+    fromStrictByteString = toGenString
+
+instance ConvStrictByteString String where
+    toStrictByteString   = SC.pack
+    fromStrictByteString = SC.unpack
+
+instance ConvStrictByteString S.ByteString where
+    toStrictByteString   = id
+    fromStrictByteString = id
+
+instance ConvStrictByteString L.ByteString where
+    toStrictByteString   = S.concat . L.toChunks
+    fromStrictByteString = toLazyByteString
+
+instance ConvStrictByteString T.Text where
+    toStrictByteString   = TE.encodeUtf8
+    fromStrictByteString = toText
+
+instance ConvLazyByteString GenString where
+    toLazyByteString   = fromGenString
+    fromLazyByteString = toGenString
+
+instance ConvLazyByteString String where
+    toLazyByteString   = LC.pack
+    fromLazyByteString = LC.unpack
+
+instance ConvLazyByteString S.ByteString where
+    toLazyByteString   = L.fromChunks . (:[])
+    fromLazyByteString = toStrictByteString
+
+instance ConvLazyByteString L.ByteString where
+    toLazyByteString   = id
+    fromLazyByteString = id
+
+instance ConvLazyByteString T.Text where
+    toLazyByteString   = toLazyByteString . toStrictByteString
+    fromLazyByteString = toText
+
+instance ConvText GenString where
+    toText   = fromGenString
+    fromText = toGenString
+
+instance ConvText String where
+    toText   = T.pack
+    fromText = T.unpack
+
+instance ConvText S.ByteString where
+    toText   = TE.decodeUtf8With TEE.lenientDecode
+    fromText = toStrictByteString
+
+instance ConvText L.ByteString where
+    toText   = toText . toStrictByteString
+    fromText = toLazyByteString
+
+instance ConvText T.Text where
+    toText   = id
+    fromText = id
+
+-- | Polymorphic container of a string
+--
+-- When operations take place on multiple 'GenString's, they are first
+-- converted to the type 'GenStringDefault', which are lazy bytestrings,
+-- whenever absolutely necessary (which includes testing for equality,
+-- appending strings, concatenating lists of strings, empty strings with
+-- 'empty', and unfolding), making them the most efficient type for this
+-- polymorphic container.
+data GenString = forall s. (StringCells s) => GenString {gen_string :: s}
+    deriving (Typeable)
+
+toGenDefaultString :: (StringCells s) => s -> GenStringDefault
+toGenDefaultString = toStringCells
+
+instance Eq GenString where
+    _a == _b = case (_a, _b) of
+        ((GenString _a), (GenString _b)) -> toGenDefaultString _a == toGenDefaultString _b
+    _a /= _b = case (_a, _b) of
+        ((GenString _a), (GenString _b)) -> toGenDefaultString _a /= toGenDefaultString _b
+
+instance StringCells GenString where
+    -- These associated types were rather arbitrarily chosen
+    type StringCellChar GenString = Char
+    type StringCellAltChar GenString = Word8
+
+    toStringCells   = fromGenString
+    fromStringCells = toGenString
+
+    cons c _s = case _s of
+        (GenString _s) -> GenString $ cons (_s `untagTypeOf` toMainChar c) _s
+    uncons _s = case _s of
+        (GenString _s) -> let (c, s') = uncons _s
+                          in  (genStringPhantom `untagTypeOf` toMainChar c, GenString s')
+    snoc _s c = case _s of
+        (GenString _s) -> GenString $ snoc _s (_s `untagTypeOf` toMainChar c)
+    unsnoc _s = case _s of
+        (GenString _s) -> let (s', c) = unsnoc _s
+                          in  (GenString s', genStringPhantom `untagTypeOf` toMainChar c)
+
+    altCons c _s = case _s of
+        (GenString _s) -> GenString $ cons (fromWord8 c) _s
+    altUncons _s = case _s of
+        (GenString _s) -> let (c, s') = uncons _s
+                          in  (genStringPhantom `untagTypeOf` toAltChar c, GenString s')
+    altSnoc _s c = case _s of
+        (GenString _s) -> GenString $ snoc _s (fromWord8 c)
+    altUnsnoc _s = case _s of
+        (GenString _s) -> let (s', c) = unsnoc _s
+                          in  (GenString s', genStringPhantom `untagTypeOf` toAltChar c)
+
+    toMainChar = Tagged . toChar
+    toAltChar  = Tagged . toWord8
+
+    append a b = case (a, b) of
+        (GenString _a, GenString _b) -> GenString $ append (toGenDefaultString _a) (toGenDefaultString _b)
+    concat ss = GenString $ concat . map toGenDefaultString $ ss
+
+    empty = GenString $ (empty :: GenStringDefault)
+    null _s = case _s of
+        (GenString _s) -> null _s
+
+    head _s = case _s of
+        (GenString _s) -> genStringPhantom `untagTypeOf` toMainChar (head _s)
+    tail _s = case _s of
+        (GenString _s) -> GenString $ tail _s
+    last _s = case _s of
+        (GenString _s) -> genStringPhantom `untagTypeOf` toMainChar (last _s)
+    init _s = case _s of
+        (GenString _s) -> GenString $ init _s
+    altHead _s = case _s of
+        (GenString _s) -> genStringPhantom `untagTypeOf` toAltChar (head _s)
+    altLast _s = case _s of
+        (GenString _s) -> genStringPhantom `untagTypeOf` toAltChar (last _s)
+
+    unfoldr       f z = GenString $ (altUnfoldr    f z  :: GenStringDefault)
+    altUnfoldr    f z = GenString $ (unfoldr       f z  :: GenStringDefault)
+    unfoldrN    n f z = GenString $ (altUnfoldrN n f z  :: GenStringDefault)
+    altUnfoldrN n f z = GenString $ (unfoldrN    n f z  :: GenStringDefault)
+
+    index _s i = case _s of
+        (GenString _s) -> genStringPhantom `untagTypeOf` toMainChar (index _s i)
+    index64 _s i = case _s of
+        (GenString _s) -> genStringPhantom `untagTypeOf` toMainChar (index64 _s i)
+    genericIndex _s i = case _s of
+        (GenString _s) -> genStringPhantom `untagTypeOf` toMainChar (genericIndex _s i)
+
+    take n _s = case _s of
+        (GenString _s) -> GenString $ take n _s
+    take64 n _s = case _s of
+        (GenString _s) -> GenString $ take64 n _s
+    genericTake n _s = case _s of
+        (GenString _s) -> GenString $ genericTake n _s
+    drop n _s = case _s of
+        (GenString _s) -> GenString $ drop n _s
+    drop64 n _s = case _s of
+        (GenString _s) -> GenString $ drop64 n _s
+    genericDrop n _s = case _s of
+        (GenString _s) -> GenString $ genericDrop n _s
+
+    length _s = case _s of
+        (GenString _s) -> length _s
+    length64 _s = case _s of
+        (GenString _s) -> length64 _s
+    genericLength _s = case _s of
+        (GenString _s) -> genericLength _s
+
+    safeUncons _s = case _s of
+        (GenString _s) -> (\(c, s') -> (genStringPhantom `untagTypeOf` toMainChar c, GenString s')) <$> safeUncons _s
+    safeUnsnoc _s = case _s of
+        (GenString _s) -> (\(s', c) -> (GenString s', genStringPhantom `untagTypeOf` toMainChar c)) <$> safeUnsnoc _s
+    safeAltUncons _s = case _s of
+        (GenString _s) -> (\(c, s') -> (genStringPhantom `untagTypeOf` toAltChar c, GenString s')) <$> safeAltUncons _s
+    safeAltUnsnoc _s = case _s of
+        (GenString _s) -> (\(s', c) -> (GenString s', genStringPhantom `untagTypeOf` toAltChar c)) <$> safeAltUnsnoc _s
+    safeHead _s = case _s of
+        (GenString _s) -> (genStringPhantom `untagTypeOf`) . toMainChar <$> safeHead _s
+    safeTail _s = case _s of
+        (GenString _s) -> GenString <$> safeTail _s
+    safeLast _s = case _s of
+        (GenString _s) -> (genStringPhantom `untagTypeOf`) . toMainChar <$> safeLast _s
+    safeInit _s = case _s of
+        (GenString _s) -> GenString <$> safeInit _s
+    safeAltHead _s = case _s of
+        (GenString _s) -> (genStringPhantom `untagTypeOf`) . toAltChar  <$> safeAltHead _s
+    safeAltLast _s = case _s of
+        (GenString _s) -> (genStringPhantom `untagTypeOf`) . toAltChar  <$> safeAltLast _s
+    safeIndex _s i = case _s of
+        (GenString _s) -> (genStringPhantom `untagTypeOf`) . toMainChar <$> safeIndex _s i
+    safeIndex64 _s i = case _s of
+        (GenString _s) -> (genStringPhantom `untagTypeOf`) . toMainChar <$> safeIndex64 _s i
+    safeGenericIndex _s i = case _s of
+        (GenString _s) -> (genStringPhantom `untagTypeOf`) . toMainChar <$> safeGenericIndex _s i
+    safeTake n _s = case _s of
+        (GenString _s) -> GenString <$> safeTake n _s
+    safeTake64 n _s = case _s of
+        (GenString _s) -> GenString <$> safeTake64 n _s
+    safeGenericTake n _s = case _s of
+        (GenString _s) -> GenString <$> safeGenericTake n _s
+    safeDrop n _s = case _s of
+        (GenString _s) -> GenString <$> safeDrop n _s
+    safeDrop64 n _s = case _s of
+        (GenString _s) -> GenString <$> safeDrop64 n _s
+    safeGenericDrop n _s = case _s of
+        (GenString _s) -> GenString <$> safeGenericDrop n _s
+    safeUncons2 _s = case _s of
+        (GenString _s) -> (\(a, b, s') -> (genStringPhantom `untagTypeOf` toMainChar a, genStringPhantom `untagTypeOf` toMainChar b, GenString s')) <$> safeUncons2 _s
+    safeUncons3 _s = case _s of
+        (GenString _s) -> (\(a, b, c, s') -> (genStringPhantom `untagTypeOf` toMainChar a, genStringPhantom `untagTypeOf` toMainChar b, genStringPhantom `untagTypeOf` toMainChar c, GenString s')) <$> safeUncons3 _s
+    safeUncons4 _s = case _s of
+        (GenString _s) -> (\(a, b, c, d, s') -> (genStringPhantom `untagTypeOf` toMainChar a, genStringPhantom `untagTypeOf` toMainChar b, genStringPhantom `untagTypeOf` toMainChar c, genStringPhantom `untagTypeOf` toMainChar d, GenString s')) <$> safeUncons4 _s
+
+    cons2 a b _s = case _s of
+        (GenString _s) -> GenString $ cons2 (_s `untagTypeOf` toMainChar a) (_s `untagTypeOf` toMainChar b) _s
+    cons3 a b c _s = case _s of
+        (GenString _s) -> GenString $ cons3 (_s `untagTypeOf` toMainChar a) (_s `untagTypeOf` toMainChar b) (_s `untagTypeOf` toMainChar c) _s
+    cons4 a b c d _s = case _s of
+        (GenString _s) -> GenString $ cons4 (_s `untagTypeOf` toMainChar a) (_s `untagTypeOf` toMainChar b) (_s `untagTypeOf` toMainChar c) (_s `untagTypeOf` toMainChar d) _s
+    uncons2 _s = case _s of
+        (GenString _s) -> let (a, b, s') = uncons2 _s
+                          in  (genStringPhantom `untagTypeOf` toMainChar a, genStringPhantom `untagTypeOf` toMainChar b, GenString s')
+    uncons3 _s = case _s of
+        (GenString _s) -> let (a, b, c, s') = uncons3 _s
+                          in  (genStringPhantom `untagTypeOf` toMainChar a, genStringPhantom `untagTypeOf` toMainChar b, genStringPhantom `untagTypeOf` toMainChar c, GenString s')
+    uncons4 _s = case _s of
+        (GenString _s) -> let (a, b, c, d, s') = uncons4 _s
+                          in  (genStringPhantom `untagTypeOf` toMainChar a, genStringPhantom `untagTypeOf` toMainChar b, genStringPhantom `untagTypeOf` toMainChar c, genStringPhantom `untagTypeOf` toMainChar d, GenString s')
+
+-- | Untag a type with a type restriction
+--
+-- The first argument is guaranteed to be ignored; thus the value 'undefined'
+-- can be passed in its place.
+untagTypeOf :: s -> Tagged s b -> b
+untagTypeOf _ = untag
+
+-- | Phantom, undefined value only used for convenience
+--
+-- Users should be careful that this value is never evaluated when using this.
+genStringPhantom :: GenString
+genStringPhantom = undefined
+
+-- | This type is used by 'GenString' when a concrete string type is needed
+type GenStringDefault = L.ByteString
diff --git a/string-class.cabal b/string-class.cabal
new file mode 100644
--- /dev/null
+++ b/string-class.cabal
@@ -0,0 +1,25 @@
+name:                  string-class
+version:               0.1.4.1
+cabal-version:         >= 1.10
+build-type:            Simple
+license:               BSD3
+license-file:          LICENSE
+copyright:             Copyright (C) 2010 Byron James Johnson
+author:                Byron James Johnson
+maintainer:            KrabbyKrap@gmail.com
+synopsis:              String class library
+description:           String class library
+category:              Data, Text
+tested-with:           GHC == 7.0.1
+
+library
+    default-language:  Haskell2010
+    hs-source-dirs:    src
+    build-depends:     base >= 4 && < 5, bytestring, text, tagged
+    exposed-modules:   Data.String.Class
+    ghc-options:       -Wall
+    other-extensions:  TypeFamilies, FlexibleContexts, TypeSynonymInstances, ExistentialQuantification, DeriveDataTypeable
+
+source-repository head
+    type:              darcs
+    location:          http://patch-tag.com/r/bob/string-class
