diff --git a/src/Data/String/Class.hs b/src/Data/String/Class.hs
--- a/src/Data/String/Class.hs
+++ b/src/Data/String/Class.hs
@@ -1,8 +1,10 @@
-{-# LANGUAGE TypeFamilies, FlexibleContexts, TypeSynonymInstances, ExistentialQuantification, DeriveDataTypeable #-}
+{-# LANGUAGE TypeFamilies, FlexibleContexts, TypeSynonymInstances, ExistentialQuantification, DeriveDataTypeable, FlexibleInstances, UndecidableInstances #-}
 
 module Data.String.Class
-    ( StringCells(..)
+    ( Stringy
+    , StringCells(..)
     , StringCell(..)
+    , StringRWIO(..)
     , ConvGenString(..)
     , ConvString(..)
     , ConvStrictByteString(..)
@@ -12,7 +14,7 @@
     , GenStringDefault
     ) where
 
-import Prelude hiding (head, tail, last, init, take, drop, length, null, concat)
+import Prelude hiding (head, tail, last, init, take, drop, length, null, concat, putStr, getContents)
 import Control.Applicative hiding (empty)
 import qualified Data.ByteString as S
 import qualified Data.ByteString.Char8 as SC
@@ -21,15 +23,24 @@
 import qualified Data.ByteString.Lazy.Char8 as LC
 import Data.Int
 import qualified Data.List as List
+import Data.Monoid
+import Data.String (IsString)
+import qualified Data.String
 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 qualified Data.Text.IO as T
 import Data.Typeable
 import Data.Word
+import qualified System.IO as IO
 
--- | 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
+-- | String super class
+class    (StringCells s, StringRWIO s) => Stringy s
+instance (StringCells s, StringRWIO s) => Stringy s
+
+-- | 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; and length, length64, or genericLength
+class (Eq s, Monoid s, IsString s, Typeable s, StringCell (StringCellChar s), StringCell (StringCellAltChar s), ConvGenString s, ConvString s, ConvStrictByteString s, ConvLazyByteString s, ConvText s) => StringCells s where
     type StringCellChar s
     type StringCellAltChar s
 
@@ -156,6 +167,11 @@
     altUncons s = (\ ~(a, s') -> (s `untagTypeOf` toAltChar a, s')) $ uncons s
     altUnsnoc s = (\ ~(s', a) -> (s', s `untagTypeOf` toAltChar a)) $ unsnoc s
 
+    append = mappend
+    concat = mconcat
+    empty  = mempty
+    null   = (== mempty)
+
     head = fst . uncons
     tail = snd . uncons
     last = snd . unsnoc
@@ -181,11 +197,14 @@
     length64      = (fromIntegral :: Integer -> Int64) . genericLength
     genericLength = fromIntegral . length
 
+    {-
+    -- More efficient default implementation provided above
     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)
@@ -314,8 +333,80 @@
     toText :: s -> T.Text
     fromText :: T.Text -> s
 
+-- | Minimal complete definition: 'hGetContents', 'hGetLine', 'hPutStr', and 'hPutStrLn'
+class StringRWIO s where
+    -- * Handles
 
+    -- | Read n bytes *or* characters, depending on the implementation into a
+    -- ByteString, directly from the specified Handle
+    --
+    -- Whether or not this function is lazy depends on the instance; laziness
+    -- is preferred.
+    hGetContents :: IO.Handle -> IO s
 
+    -- | Read a single line from a handle
+    hGetLine :: IO.Handle -> IO s
+
+    -- | Write a string to a handle
+    hPutStr :: IO.Handle -> s -> IO ()
+
+    -- | Write a string to a handle, followed by a newline
+    --
+    -- N.B.: implementations might not define this atomically.  If the state
+    -- of being atomic is necessary, one possible solution is to convert a
+    -- string to an efficient type for which 'hPutStrLn' is atomic.
+    hPutStrLn :: IO.Handle -> s -> IO ()
+
+    -- * Special cases for standard input and output
+
+    -- | Take a function of type Text -> Text as its argument
+    --
+    -- The entire input from the standard input device is passed to this
+    -- function as its argument, and the resulting string is output on the
+    -- standard output device.
+    interact :: (s -> s) -> IO ()
+    interact f = putStr . f =<< getContents
+
+    -- | Read all user input on 'stdin' as a single string
+    getContents :: IO s
+    getContents = hGetContents IO.stdin
+
+    -- | Read a single line of user input from 'stdin'
+    getLine :: IO s
+    getLine = hGetLine IO.stdin
+
+    -- | Write a string to 'stdout'
+    putStr :: s -> IO ()
+    putStr = hPutStr IO.stdout
+
+    -- | Write a string to 'stdout', followed by a newline
+    putStrLn :: s -> IO ()
+    putStrLn = hPutStrLn IO.stdout
+
+    -- *
+
+    -- | Read a file and returns the contents of the file as a string
+    --
+    -- Depending on the instance, this function might expect the file to be
+    -- non-binary.  The default definition uses 'openFile' to open the file.
+    readFile :: FilePath -> IO s
+    readFile fn = hGetContents =<< IO.openFile fn IO.ReadMode
+
+    -- | Write a string to a file
+    --
+    -- The file is truncated to zero length before writing begins.
+    -- The default definition uses 'withFile' to open the file.
+    writeFile :: FilePath -> s -> IO ()
+    writeFile fn s = IO.withFile fn IO.WriteMode $ \hdl -> hPutStr hdl s
+
+    -- | Write a string to the end of a file
+    --
+    -- The default definition uses 'withFile' to open the file.
+    appendFile :: FilePath -> s -> IO ()
+    appendFile fn s = IO.withFile fn IO.AppendMode $ \hdl -> hPutStr hdl s
+
+
+
 instance StringCells String where
     type StringCellChar    String = Char
     type StringCellAltChar String = Char
@@ -604,6 +695,141 @@
     toText   = id
     fromText = id
 
+-- |
+--
+-- This is minimally defined with 'GenStringDefault'.
+instance StringRWIO GenString where
+    hGetContents h = genStringFromConConv <$> hGetContents h
+
+    hGetLine h = genStringFromConConv <$> hGetLine h
+
+    hPutStr h s = hPutStr h (genStringConConv s)
+
+    hPutStrLn h s = hPutStrLn h (genStringConConv s)
+
+-- | Type-restricted string conversion used by 'GenString's instance definition for 'StringRWIO'
+genStringConConv :: GenString -> GenStringDefault
+genStringConConv = toStringCells
+
+-- | Type-restricted string conversion used by 'GenString's instance definition for 'StringRWIO'
+genStringFromConConv :: GenStringDefault -> GenString
+genStringFromConConv = toStringCells
+
+-- |
+--
+-- See 'System.IO for documentation of behaviour.
+instance StringRWIO String where
+    hGetContents = IO.hGetContents
+
+    hGetLine     = IO.hGetLine
+
+    hPutStr      = IO.hPutStr
+
+    hPutStrLn    = IO.hPutStrLn
+
+    interact     = IO.interact
+
+    getContents  = IO.getContents
+
+    getLine      = IO.getLine
+
+    putStr       = IO.putStr
+
+    putStrLn     = IO.putStrLn
+
+    readFile     = IO.readFile
+
+    writeFile    = IO.writeFile
+
+    appendFile   = IO.appendFile
+
+-- |
+--
+-- See 'Data.ByteString' for documentation of behaviour.
+instance StringRWIO S.ByteString where
+    hGetContents = S.hGetContents
+
+    hGetLine     = S.hGetLine
+
+    hPutStr      = S.hPutStr
+
+    hPutStrLn    = S.hPutStrLn
+
+    interact     = S.interact
+
+    getContents  = S.getContents
+
+    getLine      = S.getLine
+
+    putStr       = S.putStr
+
+    putStrLn     = S.putStrLn
+
+    readFile     = S.readFile
+
+    writeFile    = S.writeFile
+
+    appendFile   = S.appendFile
+
+-- |
+--
+-- See 'Data.ByteString.Lazy' for documentation of behaviour.
+--
+-- 'hGetLine' and 'getLine' are defined in terms of 'toStringCells' and the equivalent methods of 'Data.ByteString'.
+-- 'hPutStrLn' is defined non-atomically: it is defined as an action that puts the string and then separately puts a newline character string.
+instance StringRWIO L.ByteString where
+    hGetContents = L.hGetContents
+
+    hGetLine     = (toStringCells <$>) . S.hGetLine
+
+    hPutStr      = L.hPutStr
+
+    hPutStrLn h  = (>> hPutStr h ((toStringCells :: String -> L.ByteString) ['\n'])) . hPutStr h
+
+    interact     = L.interact
+
+    getContents  = L.getContents
+
+    getLine      = toStringCells <$> S.getLine
+
+    putStr       = L.putStr
+
+    putStrLn     = L.putStrLn
+
+    readFile     = L.readFile
+
+    writeFile    = L.writeFile
+
+    appendFile   = L.appendFile
+
+-- |
+--
+-- See 'Data.Text.IO' for documentation of behaviour.
+instance StringRWIO T.Text where
+    hGetContents = T.hGetContents
+
+    hGetLine     = T.hGetLine
+
+    hPutStr      = T.hPutStr
+
+    hPutStrLn    = T.hPutStrLn
+
+    interact     = T.interact
+
+    getContents  = T.getContents
+
+    getLine      = T.getLine
+
+    putStr       = T.putStr
+
+    putStrLn     = T.putStrLn
+
+    readFile     = T.readFile
+
+    writeFile    = T.writeFile
+
+    appendFile   = T.appendFile
+
 -- | Polymorphic container of a string
 --
 -- When operations take place on multiple 'GenString's, they are first
@@ -612,10 +838,10 @@
 -- 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}
+data GenString = forall s. (Stringy s) => GenString {gen_string :: s}
     deriving (Typeable)
 
-toGenDefaultString :: (StringCells s) => s -> GenStringDefault
+toGenDefaultString :: (Stringy s) => s -> GenStringDefault
 toGenDefaultString = toStringCells
 
 instance Eq GenString where
@@ -624,6 +850,15 @@
     _a /= _b = case (_a, _b) of
         ((GenString _a), (GenString _b)) -> toGenDefaultString _a /= toGenDefaultString _b
 
+instance IsString GenString where
+    fromString = GenString
+
+instance Monoid GenString where
+    mempty  = GenString $ (empty :: GenStringDefault)
+    mappend a b = case (a, b) of
+        (GenString _a, GenString _b) -> GenString $ append (toGenDefaultString _a) (toGenDefaultString _b)
+    mconcat ss = GenString $ concat . map toGenDefaultString $ ss
+
 instance StringCells GenString where
     -- These associated types were rather arbitrarily chosen
     type StringCellChar GenString = Char
@@ -657,11 +892,6 @@
     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
 
diff --git a/string-class.cabal b/string-class.cabal
--- a/string-class.cabal
+++ b/string-class.cabal
@@ -1,5 +1,5 @@
 name:                  string-class
-version:               0.1.4.1
+version:               0.1.5.0
 cabal-version:         >= 1.10
 build-type:            Simple
 license:               BSD3
@@ -18,7 +18,7 @@
     build-depends:     base >= 4 && < 5, bytestring, text, tagged
     exposed-modules:   Data.String.Class
     ghc-options:       -Wall
-    other-extensions:  TypeFamilies, FlexibleContexts, TypeSynonymInstances, ExistentialQuantification, DeriveDataTypeable
+    other-extensions:  TypeFamilies, FlexibleContexts, TypeSynonymInstances, ExistentialQuantification, DeriveDataTypeable, FlexibleInstances, UndecidableInstances
 
 source-repository head
     type:              darcs
