diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,7 @@
+## 0.3.1
+
+* Expose `ByteStringBuilder`
+
 ## 0.3.0
 
 * Move `Data.Sequences.Lazy` to `mono-traversable` 1.0.0
diff --git a/Data/Builder.hs b/Data/Builder.hs
deleted file mode 100644
--- a/Data/Builder.hs
+++ /dev/null
@@ -1,94 +0,0 @@
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE FunctionalDependencies #-}
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE FlexibleContexts #-}
--- | Abstraction for different kinds of builders.
---
--- Note that whenever a character encoding is used, it will be UTF8. For
--- different behavior, please use the underlying library.
-module Data.Builder
-    ( TextBuilder
-    , BlazeBuilder
-    , Builder (..)
-    , ToBuilder (..)
-    , textToBuilder
-    ) where
-
-import Data.Monoid (Monoid)
-
-import qualified Data.Text as T
-import qualified Data.Text.Lazy as TL
-import qualified Data.Text.Lazy.Builder as TB
-
-import qualified Data.ByteString as S
-import qualified Data.ByteString.Lazy as L
-import qualified Data.ByteString.Builder as BB
-import qualified Data.ByteString.Builder.Extra as BB (flush)
-
-import qualified Data.Text.Encoding as TE
-import qualified Data.Text.Lazy.Encoding as TLE
-
--- | Since 0.1.0.0
-type TextBuilder = TB.Builder
-
--- | Since 0.1.0.0
-type BlazeBuilder = BB.Builder
-
--- | Since 0.3.0.0
-type ByteStringBuilder = BB.Builder
-
--- | Since 0.1.0.0
-class Monoid builder => Builder builder lazy | builder -> lazy, lazy -> builder where
-    -- | Since 0.1.0.0
-    builderToLazy :: builder -> lazy
-
-    -- | Since 0.1.0.0
-    flushBuilder :: builder
-
-instance Builder TB.Builder TL.Text where
-    builderToLazy = TB.toLazyText
-    flushBuilder = TB.flush
-
-instance Builder BB.Builder L.ByteString where
-    builderToLazy = BB.toLazyByteString
-    flushBuilder = BB.flush
-
--- | Since 0.1.0.0
-class ToBuilder value builder where
-    -- | Since 0.1.0.0
-    toBuilder :: value -> builder
-
--- Text
-instance ToBuilder TB.Builder TB.Builder where
-    toBuilder = id
-instance ToBuilder T.Text TB.Builder where
-    toBuilder = TB.fromText
-instance ToBuilder TL.Text TB.Builder where
-    toBuilder = TB.fromLazyText
-instance ToBuilder Char TB.Builder where
-    toBuilder = TB.singleton
-instance (a ~ Char) => ToBuilder [a] TB.Builder where
-    toBuilder = TB.fromString
-
--- Blaze
-instance ToBuilder BB.Builder BB.Builder where
-    toBuilder = id
-instance ToBuilder T.Text BB.Builder where
-    toBuilder = TE.encodeUtf8Builder
-instance ToBuilder TL.Text BB.Builder where
-    toBuilder = TLE.encodeUtf8Builder
-instance ToBuilder Char BB.Builder where
-    toBuilder = toBuilder . T.singleton
-instance (a ~ Char) => ToBuilder [a] BB.Builder where
-    toBuilder = toBuilder . TL.pack
-
-instance ToBuilder S.ByteString BB.Builder where
-    toBuilder = BB.byteString
-instance ToBuilder L.ByteString BB.Builder where
-    toBuilder = BB.lazyByteString
-
--- | Provided for type disambiguation in the presence of OverloadedStrings.
---
--- Since 0.1.0.0
-textToBuilder :: ToBuilder T.Text builder => T.Text -> builder
-textToBuilder = toBuilder
diff --git a/Data/ChunkedZip.hs b/Data/ChunkedZip.hs
deleted file mode 100644
--- a/Data/ChunkedZip.hs
+++ /dev/null
@@ -1,172 +0,0 @@
--- | Various zipping and unzipping functions for chunked data structures.
-module Data.ChunkedZip where
-
-import Prelude hiding (zipWith, zipWith3)
-import Control.Arrow ((&&&), (***))
-import qualified Data.List as List
-import qualified Data.List.NonEmpty as NonEmpty
-import Data.List.NonEmpty (NonEmpty)
-import qualified Data.Vector as Vector
--- import qualified Data.Vector.Unboxed as UVector
-import qualified Data.Sequence as Seq
-import Control.Monad.Trans.Identity
-import Control.Monad.Trans.Reader
-import qualified Data.IntMap as IntMap
-import Data.Tree
-import Data.Functor.Compose
-import Data.Foldable (toList)
-
-class Functor f => Zip f where
-    zipWith :: (a -> b -> c) -> f a -> f b -> f c
-
-    zip :: f a -> f b -> f (a, b)
-    zip = zipWith (,)
-
-    zap :: f (a -> b) -> f a -> f b
-    zap = zipWith id
-
-    unzip :: f (a, b) -> (f a, f b)
-    unzip = fmap fst &&& fmap snd
-
-instance Zip [] where
-    zip = List.zip
-    zipWith = List.zipWith
-    unzip = List.unzip
-instance Zip NonEmpty where
-    zipWith = NonEmpty.zipWith
-    zip = NonEmpty.zip
-    unzip = NonEmpty.unzip
-instance Zip Seq.Seq where
-    zip = Seq.zip
-    zipWith = Seq.zipWith
-    unzip = (Seq.fromList *** Seq.fromList) . List.unzip . toList
-instance Zip Tree where
-    zipWith f (Node a as) (Node b bs) = Node (f a b) (zipWith (zipWith f) as bs)
-instance Zip Vector.Vector where
-    zip = Vector.zip
-    unzip = Vector.unzip
-    zipWith = Vector.zipWith
-  {-
-instance Zip UVector where
-    zip = UVector.zip
-    unzip = UVector.unzip
-    zipWith = UVector.zipWith
-    -}
-
-instance Zip m => Zip (IdentityT m) where
-    zipWith f (IdentityT m) (IdentityT n) = IdentityT (zipWith f m n)
-instance Zip ((->)a) where
-    zipWith f g h a = f (g a) (h a)
-instance Zip m => Zip (ReaderT e m) where
-    zipWith f (ReaderT m) (ReaderT n) = ReaderT $ \a ->
-      zipWith f (m a) (n a)
-instance Zip IntMap.IntMap where
-    zipWith = IntMap.intersectionWith
-instance (Zip f, Zip g) => Zip (Compose f g) where
-    zipWith f (Compose a) (Compose b) = Compose $ zipWith (zipWith f) a b
-
-class Functor f => Zip3 f where
-    zipWith3 :: (a -> b -> c -> d) -> f a -> f b -> f c -> f d
-
-    zip3 :: f a -> f b -> f c -> f (a, b, c)
-    zip3 = zipWith3 (\x y z -> (x,y,z))
-
-    zap3 :: f (a -> b -> c) -> f a -> f b -> f c
-    zap3 = zipWith3 id
-
-    unzip3 :: f (a, b, c) -> (f a, f b, f c)
-    -- unzip3 = fmap (\(x,_,_)->x) &&& fmap (\(_,x,_)->x) &&& fmap (\(_,_,x)->x)
-
-instance Zip3 [] where
-    zip3 = List.zip3
-    unzip3 = List.unzip3
-    zipWith3 = List.zipWith3
-instance Zip3 Vector.Vector where
-    zip3 = Vector.zip3
-    unzip3 = Vector.unzip3
-    zipWith3 = Vector.zipWith3
-instance Zip3 Seq.Seq where
-    zip3 = Seq.zip3
-    unzip3 = (\(a, b, c) -> (Seq.fromList a, Seq.fromList b, Seq.fromList c)) . List.unzip3 . toList
-    zipWith3 = Seq.zipWith3
-
-class Functor f => Zip4 f where
-    zipWith4 :: (a -> b -> c -> d -> e) -> f a -> f b -> f c -> f d -> f e
-
-    zip4 :: f a -> f b -> f c -> f d ->  f (a, b, c, d)
-    zip4 = zipWith4 (\w x y z -> (w, x,y,z))
-
-    zap4 :: f (a -> b -> c -> d) -> f a -> f b -> f c -> f d
-    zap4 = zipWith4 id
-
-    unzip4 :: f (a, b, c, d) -> (f a, f b, f c, f d)
-
-instance Zip4 [] where
-    zip4 = List.zip4
-    unzip4 = List.unzip4
-    zipWith4 = List.zipWith4
-instance Zip4 Vector.Vector where
-    zip4 = Vector.zip4
-    unzip4 = Vector.unzip4
-    zipWith4 = Vector.zipWith4
-instance Zip4 Seq.Seq where
-    zip4 = Seq.zip4
-    unzip4 = (\(a, b, c, d) -> (Seq.fromList a, Seq.fromList b, Seq.fromList c, Seq.fromList d)) . List.unzip4 . toList
-    zipWith4 = Seq.zipWith4
-
-class Functor f => Zip5 f where
-    zipWith5 :: (a -> b -> c -> d -> e -> g) -> f a -> f b -> f c -> f d -> f e -> f g
-
-    zip5 :: f a -> f b -> f c -> f d -> f e -> f (a, b, c, d, e)
-    zip5 = zipWith5 (\v w x y z -> (v,w,x,y,z))
-
-    zap5 :: f (a -> b -> c -> d -> e) -> f a -> f b -> f c -> f d -> f e
-    zap5 = zipWith5 id
-
-    unzip5 :: f (a, b, c, d, e) -> (f a, f b, f c, f d, f e)
-
-instance Zip5 [] where
-    zip5 = List.zip5
-    unzip5 = List.unzip5
-    zipWith5 = List.zipWith5
-instance Zip5 Vector.Vector where
-    zip5 = Vector.zip5
-    unzip5 = Vector.unzip5
-    zipWith5 = Vector.zipWith5
-
-class Functor f => Zip6 f where
-    zipWith6 :: (a -> b -> c -> d -> e -> g -> h) -> f a -> f b -> f c -> f d -> f e -> f g -> f h
-
-    zip6 :: f a -> f b -> f c -> f d -> f e -> f g -> f (a, b, c, d, e, g)
-    zip6 = zipWith6 (\u v w x y z -> (u, v,w,x,y,z))
-
-    zap6 :: f (a -> b -> c -> d -> e -> g) -> f a -> f b -> f c -> f d -> f e -> f g
-    zap6 = zipWith6 id
-
-    unzip6 :: f (a, b, c, d, e, g) -> (f a, f b, f c, f d, f e, f g)
-
-instance Zip6 [] where
-    zip6 = List.zip6
-    unzip6 = List.unzip6
-    zipWith6 = List.zipWith6
-instance Zip6 Vector.Vector where
-    zip6 = Vector.zip6
-    unzip6 = Vector.unzip6
-    zipWith6 = Vector.zipWith6
-
-class Functor f => Zip7 f where
-    zipWith7 :: (a -> b -> c -> d -> e -> g -> h -> i) -> f a -> f b -> f c -> f d -> f e -> f g -> f h -> f i
-
-    zip7 :: f a -> f b -> f c -> f d -> f e -> f g -> f h -> f (a, b, c, d, e, g, h)
-    zip7 = zipWith7 (\t u v w x y z -> (t,u,v,w,x,y,z))
-
-    zap7 :: f (a -> b -> c -> d -> e -> g -> h) -> f a -> f b -> f c -> f d -> f e -> f g -> f h
-    zap7 = zipWith7 id
-
-    unzip7 :: f (a, b, c, d, e, g, h) -> (f a, f b, f c, f d, f e, f g, f h)
-    -- unzip3 = fmap (\(x,_,_)->x) &&& fmap (\(_,x,_)->x) &&& fmap (\(_,_,x)->x)
-
-instance Zip7 [] where
-    zip7 = List.zip7
-    unzip7 = List.unzip7
-    zipWith7 = List.zipWith7
diff --git a/Data/IOData.hs b/Data/IOData.hs
deleted file mode 100644
--- a/Data/IOData.hs
+++ /dev/null
@@ -1,95 +0,0 @@
-{-# LANGUAGE CPP          #-}
-{-# LANGUAGE TypeFamilies #-}
-module Data.IOData where
-
-import           Control.Monad                 (liftM)
-import           Control.Monad.IO.Class
-import qualified Data.ByteString               as ByteString
-import qualified Data.ByteString.Char8         as ByteString8
-import qualified Data.ByteString.Lazy          as LByteString
-import           Data.ByteString.Lazy.Internal (defaultChunkSize)
-import qualified Data.Text                     as Text
-import qualified Data.Text.IO                  as Text
-import qualified Data.Text.Lazy                as LText
-import qualified Data.Text.Lazy.IO             as LText
-import           Prelude                       (Char, flip, ($), (.), FilePath)
-import qualified Prelude
-import           System.IO                     (Handle)
-import qualified System.IO
-
-#if !MIN_VERSION_text(0, 11, 3)
-import           Control.Exception             (handle, throwIO)
-import           System.IO.Error               (isEOFError)
-#endif
-
--- | Data which can be read to and from files and handles.
---
--- Note that, for lazy sequences, these operations may perform
--- lazy I\/O.
-class IOData a where
-    readFile     :: MonadIO m => FilePath -> m a
-    writeFile    :: MonadIO m => FilePath -> a -> m ()
-    getLine      :: MonadIO m => m a
-    hGetContents :: MonadIO m => Handle -> m a
-    hGetLine     :: MonadIO m => Handle -> m a
-    hPut         :: MonadIO m => Handle -> a -> m ()
-    hPutStrLn    :: MonadIO m => Handle -> a -> m ()
-    hGetChunk    :: MonadIO m => Handle -> m a
-instance IOData ByteString.ByteString where
-    readFile = liftIO . ByteString.readFile
-    writeFile fp = liftIO . ByteString.writeFile fp
-    getLine = liftIO ByteString.getLine
-    hGetContents = liftIO . ByteString.hGetContents
-    hGetLine = liftIO . ByteString.hGetLine
-    hPut h = liftIO . ByteString.hPut h
-    hPutStrLn h = liftIO . ByteString8.hPutStrLn h
-    hGetChunk = liftIO . flip ByteString.hGetSome defaultChunkSize
-instance IOData LByteString.ByteString where
-    readFile = liftIO . LByteString.readFile
-    writeFile fp = liftIO . LByteString.writeFile fp
-    getLine = liftM LByteString.fromStrict (liftIO ByteString.getLine)
-    hGetContents = liftIO . LByteString.hGetContents
-    hGetLine = liftM LByteString.fromStrict . liftIO . ByteString.hGetLine
-    hPut h = liftIO . LByteString.hPut h
-    hPutStrLn h lbs = liftIO $ do
-        LByteString.hPutStr h lbs
-        ByteString8.hPutStrLn h ByteString.empty
-    hGetChunk = liftM LByteString.fromStrict . hGetChunk
-instance IOData Text.Text where
-    readFile = liftIO . Text.readFile
-    writeFile fp = liftIO . Text.writeFile fp
-    getLine = liftIO Text.getLine
-    hGetContents = liftIO . Text.hGetContents
-    hGetLine = liftIO . Text.hGetLine
-    hPut h = liftIO . Text.hPutStr h
-    hPutStrLn h = liftIO . Text.hPutStrLn h
-#if MIN_VERSION_text(0, 11, 3)
-    hGetChunk = liftIO . Text.hGetChunk
-#else
-    -- Dangerously inefficient!
-    hGetChunk =
-        liftIO . handleEOF . liftM Text.singleton . System.IO.hGetChar
-      where
-        handleEOF = handle $ \e ->
-            if isEOFError e
-                then Prelude.return Text.empty
-                else throwIO e
-#endif
-instance IOData LText.Text where
-    readFile = liftIO . LText.readFile
-    writeFile fp = liftIO . LText.writeFile fp
-    getLine = liftIO LText.getLine
-    hGetContents = liftIO . LText.hGetContents
-    hGetLine = liftIO . LText.hGetLine
-    hPut h = liftIO . LText.hPutStr h
-    hPutStrLn h = liftIO . LText.hPutStrLn h
-    hGetChunk = liftM LText.fromStrict . hGetChunk
-instance (Char ~ c) => IOData [c] where
-    readFile = liftIO . Prelude.readFile
-    writeFile fp = liftIO . Prelude.writeFile fp
-    getLine = liftIO Prelude.getLine
-    hGetContents = liftIO . System.IO.hGetContents
-    hGetLine = liftIO . System.IO.hGetLine
-    hPut h = liftIO . System.IO.hPutStr h
-    hPutStrLn h = liftIO . System.IO.hPutStrLn h
-    hGetChunk = liftM Text.unpack . hGetChunk
diff --git a/chunked-data.cabal b/chunked-data.cabal
--- a/chunked-data.cabal
+++ b/chunked-data.cabal
@@ -1,29 +1,46 @@
-name:                chunked-data
-version:             0.3.0
-synopsis:            Typeclasses for dealing with various chunked data representations
-description:         Originally present in classy-prelude.
-homepage:            https://github.com/snoyberg/mono-traversable
-license:             MIT
-license-file:        LICENSE
-author:              Michael Snoyman
-maintainer:          michael@snoyman.com
-category:            Data
-build-type:          Simple
-cabal-version:       >=1.8
-extra-source-files:  README.md ChangeLog.md
+-- This file has been generated from package.yaml by hpack version 0.20.0.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: a27d451194c09c28477e2c3e5a83512c2408ab49736af80656d4ee0811a3be53
 
-library
-  exposed-modules:     Data.IOData
-                       Data.Builder
-                       Data.ChunkedZip
-  build-depends:       base >= 4 && < 5
-                     , transformers
-                     , bytestring >= 0.10.2
-                     , text >= 1.2
-                     , containers
-                     , vector
-                     , semigroups
+name:           chunked-data
+version:        0.3.1
+synopsis:       Typeclasses for dealing with various chunked data representations
+description:    See docs and README at <http://www.stackage.org/package/chunked-data>
+category:       Data
+homepage:       https://github.com/snoyberg/mono-traversable#readme
+bug-reports:    https://github.com/snoyberg/mono-traversable/issues
+author:         Michael Snoyman
+maintainer:     michael@snoyman.com
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
 
+extra-source-files:
+    ChangeLog.md
+    README.md
+
 source-repository head
-  type:     git
-  location: https://github.com/snoyberg/mono-traversable.git
+  type: git
+  location: https://github.com/snoyberg/mono-traversable
+
+library
+  hs-source-dirs:
+      src
+  build-depends:
+      base >=4 && <5
+    , bytestring >=0.10.2
+    , containers
+    , semigroups
+    , text >=1.2
+    , transformers
+    , vector
+  exposed-modules:
+      Data.Builder
+      Data.ChunkedZip
+      Data.IOData
+  other-modules:
+      Paths_chunked_data
+  default-language: Haskell2010
diff --git a/src/Data/Builder.hs b/src/Data/Builder.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Builder.hs
@@ -0,0 +1,95 @@
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE FlexibleContexts #-}
+-- | Abstraction for different kinds of builders.
+--
+-- Note that whenever a character encoding is used, it will be UTF8. For
+-- different behavior, please use the underlying library.
+module Data.Builder
+    ( TextBuilder
+    , BlazeBuilder
+    , ByteStringBuilder
+    , Builder (..)
+    , ToBuilder (..)
+    , textToBuilder
+    ) where
+
+import Data.Monoid (Monoid)
+
+import qualified Data.Text as T
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Builder as TB
+
+import qualified Data.ByteString as S
+import qualified Data.ByteString.Lazy as L
+import qualified Data.ByteString.Builder as BB
+import qualified Data.ByteString.Builder.Extra as BB (flush)
+
+import qualified Data.Text.Encoding as TE
+import qualified Data.Text.Lazy.Encoding as TLE
+
+-- | Since 0.1.0.0
+type TextBuilder = TB.Builder
+
+-- | Since 0.1.0.0
+type BlazeBuilder = BB.Builder
+
+-- | Since 0.3.0.0
+type ByteStringBuilder = BB.Builder
+
+-- | Since 0.1.0.0
+class Monoid builder => Builder builder lazy | builder -> lazy, lazy -> builder where
+    -- | Since 0.1.0.0
+    builderToLazy :: builder -> lazy
+
+    -- | Since 0.1.0.0
+    flushBuilder :: builder
+
+instance Builder TB.Builder TL.Text where
+    builderToLazy = TB.toLazyText
+    flushBuilder = TB.flush
+
+instance Builder BB.Builder L.ByteString where
+    builderToLazy = BB.toLazyByteString
+    flushBuilder = BB.flush
+
+-- | Since 0.1.0.0
+class ToBuilder value builder where
+    -- | Since 0.1.0.0
+    toBuilder :: value -> builder
+
+-- Text
+instance ToBuilder TB.Builder TB.Builder where
+    toBuilder = id
+instance ToBuilder T.Text TB.Builder where
+    toBuilder = TB.fromText
+instance ToBuilder TL.Text TB.Builder where
+    toBuilder = TB.fromLazyText
+instance ToBuilder Char TB.Builder where
+    toBuilder = TB.singleton
+instance (a ~ Char) => ToBuilder [a] TB.Builder where
+    toBuilder = TB.fromString
+
+-- Blaze
+instance ToBuilder BB.Builder BB.Builder where
+    toBuilder = id
+instance ToBuilder T.Text BB.Builder where
+    toBuilder = TE.encodeUtf8Builder
+instance ToBuilder TL.Text BB.Builder where
+    toBuilder = TLE.encodeUtf8Builder
+instance ToBuilder Char BB.Builder where
+    toBuilder = toBuilder . T.singleton
+instance (a ~ Char) => ToBuilder [a] BB.Builder where
+    toBuilder = toBuilder . TL.pack
+
+instance ToBuilder S.ByteString BB.Builder where
+    toBuilder = BB.byteString
+instance ToBuilder L.ByteString BB.Builder where
+    toBuilder = BB.lazyByteString
+
+-- | Provided for type disambiguation in the presence of OverloadedStrings.
+--
+-- Since 0.1.0.0
+textToBuilder :: ToBuilder T.Text builder => T.Text -> builder
+textToBuilder = toBuilder
diff --git a/src/Data/ChunkedZip.hs b/src/Data/ChunkedZip.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/ChunkedZip.hs
@@ -0,0 +1,172 @@
+-- | Various zipping and unzipping functions for chunked data structures.
+module Data.ChunkedZip where
+
+import Prelude hiding (zipWith, zipWith3)
+import Control.Arrow ((&&&), (***))
+import qualified Data.List as List
+import qualified Data.List.NonEmpty as NonEmpty
+import Data.List.NonEmpty (NonEmpty)
+import qualified Data.Vector as Vector
+-- import qualified Data.Vector.Unboxed as UVector
+import qualified Data.Sequence as Seq
+import Control.Monad.Trans.Identity
+import Control.Monad.Trans.Reader
+import qualified Data.IntMap as IntMap
+import Data.Tree
+import Data.Functor.Compose
+import Data.Foldable (toList)
+
+class Functor f => Zip f where
+    zipWith :: (a -> b -> c) -> f a -> f b -> f c
+
+    zip :: f a -> f b -> f (a, b)
+    zip = zipWith (,)
+
+    zap :: f (a -> b) -> f a -> f b
+    zap = zipWith id
+
+    unzip :: f (a, b) -> (f a, f b)
+    unzip = fmap fst &&& fmap snd
+
+instance Zip [] where
+    zip = List.zip
+    zipWith = List.zipWith
+    unzip = List.unzip
+instance Zip NonEmpty where
+    zipWith = NonEmpty.zipWith
+    zip = NonEmpty.zip
+    unzip = NonEmpty.unzip
+instance Zip Seq.Seq where
+    zip = Seq.zip
+    zipWith = Seq.zipWith
+    unzip = (Seq.fromList *** Seq.fromList) . List.unzip . toList
+instance Zip Tree where
+    zipWith f (Node a as) (Node b bs) = Node (f a b) (zipWith (zipWith f) as bs)
+instance Zip Vector.Vector where
+    zip = Vector.zip
+    unzip = Vector.unzip
+    zipWith = Vector.zipWith
+  {-
+instance Zip UVector where
+    zip = UVector.zip
+    unzip = UVector.unzip
+    zipWith = UVector.zipWith
+    -}
+
+instance Zip m => Zip (IdentityT m) where
+    zipWith f (IdentityT m) (IdentityT n) = IdentityT (zipWith f m n)
+instance Zip ((->)a) where
+    zipWith f g h a = f (g a) (h a)
+instance Zip m => Zip (ReaderT e m) where
+    zipWith f (ReaderT m) (ReaderT n) = ReaderT $ \a ->
+      zipWith f (m a) (n a)
+instance Zip IntMap.IntMap where
+    zipWith = IntMap.intersectionWith
+instance (Zip f, Zip g) => Zip (Compose f g) where
+    zipWith f (Compose a) (Compose b) = Compose $ zipWith (zipWith f) a b
+
+class Functor f => Zip3 f where
+    zipWith3 :: (a -> b -> c -> d) -> f a -> f b -> f c -> f d
+
+    zip3 :: f a -> f b -> f c -> f (a, b, c)
+    zip3 = zipWith3 (\x y z -> (x,y,z))
+
+    zap3 :: f (a -> b -> c) -> f a -> f b -> f c
+    zap3 = zipWith3 id
+
+    unzip3 :: f (a, b, c) -> (f a, f b, f c)
+    -- unzip3 = fmap (\(x,_,_)->x) &&& fmap (\(_,x,_)->x) &&& fmap (\(_,_,x)->x)
+
+instance Zip3 [] where
+    zip3 = List.zip3
+    unzip3 = List.unzip3
+    zipWith3 = List.zipWith3
+instance Zip3 Vector.Vector where
+    zip3 = Vector.zip3
+    unzip3 = Vector.unzip3
+    zipWith3 = Vector.zipWith3
+instance Zip3 Seq.Seq where
+    zip3 = Seq.zip3
+    unzip3 = (\(a, b, c) -> (Seq.fromList a, Seq.fromList b, Seq.fromList c)) . List.unzip3 . toList
+    zipWith3 = Seq.zipWith3
+
+class Functor f => Zip4 f where
+    zipWith4 :: (a -> b -> c -> d -> e) -> f a -> f b -> f c -> f d -> f e
+
+    zip4 :: f a -> f b -> f c -> f d ->  f (a, b, c, d)
+    zip4 = zipWith4 (\w x y z -> (w, x,y,z))
+
+    zap4 :: f (a -> b -> c -> d) -> f a -> f b -> f c -> f d
+    zap4 = zipWith4 id
+
+    unzip4 :: f (a, b, c, d) -> (f a, f b, f c, f d)
+
+instance Zip4 [] where
+    zip4 = List.zip4
+    unzip4 = List.unzip4
+    zipWith4 = List.zipWith4
+instance Zip4 Vector.Vector where
+    zip4 = Vector.zip4
+    unzip4 = Vector.unzip4
+    zipWith4 = Vector.zipWith4
+instance Zip4 Seq.Seq where
+    zip4 = Seq.zip4
+    unzip4 = (\(a, b, c, d) -> (Seq.fromList a, Seq.fromList b, Seq.fromList c, Seq.fromList d)) . List.unzip4 . toList
+    zipWith4 = Seq.zipWith4
+
+class Functor f => Zip5 f where
+    zipWith5 :: (a -> b -> c -> d -> e -> g) -> f a -> f b -> f c -> f d -> f e -> f g
+
+    zip5 :: f a -> f b -> f c -> f d -> f e -> f (a, b, c, d, e)
+    zip5 = zipWith5 (\v w x y z -> (v,w,x,y,z))
+
+    zap5 :: f (a -> b -> c -> d -> e) -> f a -> f b -> f c -> f d -> f e
+    zap5 = zipWith5 id
+
+    unzip5 :: f (a, b, c, d, e) -> (f a, f b, f c, f d, f e)
+
+instance Zip5 [] where
+    zip5 = List.zip5
+    unzip5 = List.unzip5
+    zipWith5 = List.zipWith5
+instance Zip5 Vector.Vector where
+    zip5 = Vector.zip5
+    unzip5 = Vector.unzip5
+    zipWith5 = Vector.zipWith5
+
+class Functor f => Zip6 f where
+    zipWith6 :: (a -> b -> c -> d -> e -> g -> h) -> f a -> f b -> f c -> f d -> f e -> f g -> f h
+
+    zip6 :: f a -> f b -> f c -> f d -> f e -> f g -> f (a, b, c, d, e, g)
+    zip6 = zipWith6 (\u v w x y z -> (u, v,w,x,y,z))
+
+    zap6 :: f (a -> b -> c -> d -> e -> g) -> f a -> f b -> f c -> f d -> f e -> f g
+    zap6 = zipWith6 id
+
+    unzip6 :: f (a, b, c, d, e, g) -> (f a, f b, f c, f d, f e, f g)
+
+instance Zip6 [] where
+    zip6 = List.zip6
+    unzip6 = List.unzip6
+    zipWith6 = List.zipWith6
+instance Zip6 Vector.Vector where
+    zip6 = Vector.zip6
+    unzip6 = Vector.unzip6
+    zipWith6 = Vector.zipWith6
+
+class Functor f => Zip7 f where
+    zipWith7 :: (a -> b -> c -> d -> e -> g -> h -> i) -> f a -> f b -> f c -> f d -> f e -> f g -> f h -> f i
+
+    zip7 :: f a -> f b -> f c -> f d -> f e -> f g -> f h -> f (a, b, c, d, e, g, h)
+    zip7 = zipWith7 (\t u v w x y z -> (t,u,v,w,x,y,z))
+
+    zap7 :: f (a -> b -> c -> d -> e -> g -> h) -> f a -> f b -> f c -> f d -> f e -> f g -> f h
+    zap7 = zipWith7 id
+
+    unzip7 :: f (a, b, c, d, e, g, h) -> (f a, f b, f c, f d, f e, f g, f h)
+    -- unzip3 = fmap (\(x,_,_)->x) &&& fmap (\(_,x,_)->x) &&& fmap (\(_,_,x)->x)
+
+instance Zip7 [] where
+    zip7 = List.zip7
+    unzip7 = List.unzip7
+    zipWith7 = List.zipWith7
diff --git a/src/Data/IOData.hs b/src/Data/IOData.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/IOData.hs
@@ -0,0 +1,95 @@
+{-# LANGUAGE CPP          #-}
+{-# LANGUAGE TypeFamilies #-}
+module Data.IOData where
+
+import           Control.Monad                 (liftM)
+import           Control.Monad.IO.Class
+import qualified Data.ByteString               as ByteString
+import qualified Data.ByteString.Char8         as ByteString8
+import qualified Data.ByteString.Lazy          as LByteString
+import           Data.ByteString.Lazy.Internal (defaultChunkSize)
+import qualified Data.Text                     as Text
+import qualified Data.Text.IO                  as Text
+import qualified Data.Text.Lazy                as LText
+import qualified Data.Text.Lazy.IO             as LText
+import           Prelude                       (Char, flip, ($), (.), FilePath)
+import qualified Prelude
+import           System.IO                     (Handle)
+import qualified System.IO
+
+#if !MIN_VERSION_text(0, 11, 3)
+import           Control.Exception             (handle, throwIO)
+import           System.IO.Error               (isEOFError)
+#endif
+
+-- | Data which can be read to and from files and handles.
+--
+-- Note that, for lazy sequences, these operations may perform
+-- lazy I\/O.
+class IOData a where
+    readFile     :: MonadIO m => FilePath -> m a
+    writeFile    :: MonadIO m => FilePath -> a -> m ()
+    getLine      :: MonadIO m => m a
+    hGetContents :: MonadIO m => Handle -> m a
+    hGetLine     :: MonadIO m => Handle -> m a
+    hPut         :: MonadIO m => Handle -> a -> m ()
+    hPutStrLn    :: MonadIO m => Handle -> a -> m ()
+    hGetChunk    :: MonadIO m => Handle -> m a
+instance IOData ByteString.ByteString where
+    readFile = liftIO . ByteString.readFile
+    writeFile fp = liftIO . ByteString.writeFile fp
+    getLine = liftIO ByteString.getLine
+    hGetContents = liftIO . ByteString.hGetContents
+    hGetLine = liftIO . ByteString.hGetLine
+    hPut h = liftIO . ByteString.hPut h
+    hPutStrLn h = liftIO . ByteString8.hPutStrLn h
+    hGetChunk = liftIO . flip ByteString.hGetSome defaultChunkSize
+instance IOData LByteString.ByteString where
+    readFile = liftIO . LByteString.readFile
+    writeFile fp = liftIO . LByteString.writeFile fp
+    getLine = liftM LByteString.fromStrict (liftIO ByteString.getLine)
+    hGetContents = liftIO . LByteString.hGetContents
+    hGetLine = liftM LByteString.fromStrict . liftIO . ByteString.hGetLine
+    hPut h = liftIO . LByteString.hPut h
+    hPutStrLn h lbs = liftIO $ do
+        LByteString.hPutStr h lbs
+        ByteString8.hPutStrLn h ByteString.empty
+    hGetChunk = liftM LByteString.fromStrict . hGetChunk
+instance IOData Text.Text where
+    readFile = liftIO . Text.readFile
+    writeFile fp = liftIO . Text.writeFile fp
+    getLine = liftIO Text.getLine
+    hGetContents = liftIO . Text.hGetContents
+    hGetLine = liftIO . Text.hGetLine
+    hPut h = liftIO . Text.hPutStr h
+    hPutStrLn h = liftIO . Text.hPutStrLn h
+#if MIN_VERSION_text(0, 11, 3)
+    hGetChunk = liftIO . Text.hGetChunk
+#else
+    -- Dangerously inefficient!
+    hGetChunk =
+        liftIO . handleEOF . liftM Text.singleton . System.IO.hGetChar
+      where
+        handleEOF = handle $ \e ->
+            if isEOFError e
+                then Prelude.return Text.empty
+                else throwIO e
+#endif
+instance IOData LText.Text where
+    readFile = liftIO . LText.readFile
+    writeFile fp = liftIO . LText.writeFile fp
+    getLine = liftIO LText.getLine
+    hGetContents = liftIO . LText.hGetContents
+    hGetLine = liftIO . LText.hGetLine
+    hPut h = liftIO . LText.hPutStr h
+    hPutStrLn h = liftIO . LText.hPutStrLn h
+    hGetChunk = liftM LText.fromStrict . hGetChunk
+instance (Char ~ c) => IOData [c] where
+    readFile = liftIO . Prelude.readFile
+    writeFile fp = liftIO . Prelude.writeFile fp
+    getLine = liftIO Prelude.getLine
+    hGetContents = liftIO . System.IO.hGetContents
+    hGetLine = liftIO . System.IO.hGetLine
+    hPut h = liftIO . System.IO.hPutStr h
+    hPutStrLn h = liftIO . System.IO.hPutStrLn h
+    hGetChunk = liftM Text.unpack . hGetChunk
