diff --git a/.travis.yml b/.travis.yml
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,5 @@
-language: haskell
+# See https://github.com/hvr/multi-ghc-travis for more information
+
 notifications:
   irc:
     channels:
@@ -6,3 +7,46 @@
     skip_join: true
     template:
       - "\x0313bifunctors\x03/\x0306%{branch}\x03 \x0314%{commit}\x03 %{build_url} %{message}"
+
+env:
+ # - GHCVER=7.0.1
+ # - GHCVER=7.0.2
+ # - GHCVER=7.0.3
+ # - GHCVER=7.0.4
+ # - GHCVER=7.2.1
+ # - GHCVER=7.2.2
+ - GHCVER=7.4.1
+ - GHCVER=7.4.2
+ - GHCVER=7.6.1
+ - GHCVER=7.6.2
+ - GHCVER=7.6.3
+ - GHCVER=head
+
+matrix:
+  allow_failures:
+   - env: GHCVER=head
+
+before_install:
+ - sudo add-apt-repository -y ppa:hvr/ghc
+ - sudo apt-get update
+ - sudo apt-get install cabal-install-1.18 ghc-$GHCVER
+ - export PATH=/opt/ghc/$GHCVER/bin:$PATH
+
+install:
+ - cabal-1.18 update
+ - cabal-1.18 install --only-dependencies --enable-tests
+
+script:
+ - cabal-1.18 configure --enable-tests -v2
+ - cabal-1.18 build
+ - cabal-1.18 test
+ - cabal-1.18 check
+ - cabal-1.18 sdist
+ - export SRC_TGZ=$(cabal-1.18 info . | awk '{print $2 ".tar.gz";exit}') ;
+   cd dist/;
+   if [ -f "$SRC_TGZ" ]; then
+      cabal-1.18 install "$SRC_TGZ";
+   else
+      echo "expected '$SRC_TGZ' not found";
+      exit 1;
+   fi
diff --git a/bifunctors.cabal b/bifunctors.cabal
--- a/bifunctors.cabal
+++ b/bifunctors.cabal
@@ -1,6 +1,6 @@
 name:          bifunctors
 category:      Data, Functors
-version:       4.1.1
+version:       4.1.1.1
 license:       BSD3
 cabal-version: >= 1.6
 license-file:  LICENSE
diff --git a/src/Data/Bifoldable.hs b/src/Data/Bifoldable.hs
--- a/src/Data/Bifoldable.hs
+++ b/src/Data/Bifoldable.hs
@@ -32,19 +32,56 @@
 import Data.Monoid
 import Data.Tagged
 
+-- | Minimal definition either 'bifoldr' or 'bifoldMap'
+
+-- | 'Bifoldable' identifies foldable structures with two different varieties of
+-- elements. Common examples are 'Either' and '(,)':
+--
+-- > instance Bifoldable Either where
+-- >   bifoldMap f _ (Left  a) = f a
+-- >   bifoldMap _ g (Right b) = g b
+-- >
+-- > instance Bifoldable (,) where
+-- >   bifoldr f g z (a, b) = f a (g b z)
+--
+-- When defining more than the minimal set of definitions, one should ensure
+-- that the following identities hold:
+--
+-- @
+-- 'bifold' ≡ 'bifoldMap' 'id' 'id'
+-- 'bifoldMap' f g ≡ 'bifoldr' ('mappend' . f) ('mappend' . g) 'mempty'
+-- 'bifoldr' f g z t ≡ 'appEndo' ('bifoldMap' (Endo . f) (Endo . g) t) z
+-- @
 class Bifoldable p where
+  -- | Combines the elements of a structure using a monoid.
+  --
+  -- @'bifold' ≡ 'bifoldMap' 'id' 'id'@
   bifold :: Monoid m => p m m -> m
   bifold = bifoldMap id id
   {-# INLINE bifold #-}
 
+  -- | Combines the elements of a structure, given ways of mapping them to a
+  -- common monoid.
+  --
+  -- @'bifoldMap' f g ≡ 'bifoldr' ('mappend' . f) ('mappend' . g) 'mempty'@
   bifoldMap :: Monoid m => (a -> m) -> (b -> m) -> p a b -> m
   bifoldMap f g = bifoldr (mappend . f) (mappend . g) mempty
   {-# INLINE bifoldMap #-}
 
+  -- | Combines the elements of a structure in a right associative manner. Given
+  -- a hypothetical function @toEitherList :: p a b -> [Either a b]@ yielding a
+  -- list of all elements of a structure in order, the following would hold:
+  --
+  -- @'bifoldr' f g z ≡ 'foldr' ('either' f g) z . toEitherList@
   bifoldr :: (a -> c -> c) -> (b -> c -> c) -> c -> p a b -> c
   bifoldr f g z t = appEndo (bifoldMap (Endo . f) (Endo . g) t) z
   {-# INLINE bifoldr #-}
 
+  -- | Combines the elments of a structure in a left associative manner. Given a
+  -- hypothetical function @toEitherList :: p a b -> [Either a b]@ yielding a
+  -- list of all elements of a structure in order, the following would hold:
+  --
+  -- @'bifoldl' f g z ≡ 'foldl' (\acc -> 'either' (f acc) (g acc)) z .  toEitherList@
   bifoldl :: (c -> a -> c) -> (c -> b -> c) -> c -> p a b -> c
   bifoldl f g z t = appEndo (getDual (bifoldMap (Dual . Endo . flip f) (Dual . Endo . flip g) t)) z
   {-# INLINE bifoldl #-}
@@ -78,70 +115,93 @@
   bifoldMap _ g (Right b) = g b
   {-# INLINE bifoldMap #-}
 
+-- | As 'bifoldr', but strict in the result of the reduction functions at each
+-- step.
 bifoldr' :: Bifoldable t => (a -> c -> c) -> (b -> c -> c) -> c -> t a b -> c
 bifoldr' f g z0 xs = bifoldl f' g' id xs z0 where
   f' k x z = k $! f x z
   g' k x z = k $! g x z
 {-# INLINE bifoldr' #-}
 
+-- | Right associative monadic bifold over a structure.
 bifoldrM :: (Bifoldable t, Monad m) => (a -> c -> m c) -> (b -> c -> m c) -> c -> t a b -> m c
 bifoldrM f g z0 xs = bifoldl f' g' return xs z0 where
   f' k x z = f x z >>= k
   g' k x z = g x z >>= k
 {-# INLINE bifoldrM #-}
 
+-- | As 'bifoldl', but strict in the result of the reductionf unctions at each
+-- step.
 bifoldl':: Bifoldable t => (a -> b -> a) -> (a -> c -> a) -> a -> t b c -> a
 bifoldl' f g z0 xs = bifoldr f' g' id xs z0 where
   f' x k z = k $! f z x
   g' x k z = k $! g z x
 {-# INLINE bifoldl' #-}
 
+-- | Left associative monadic bifold over a structure.
 bifoldlM :: (Bifoldable t, Monad m) => (a -> b -> m a) -> (a -> c -> m a) -> a -> t b c -> m a
 bifoldlM f g z0 xs = bifoldr f' g' return xs z0 where
   f' x k z = f z x >>= k
   g' x k z = g z x >>= k
 {-# INLINE bifoldlM #-}
 
+-- | As 'Data.Bitraversable.bitraverse', but ignores the results of the
+-- functions, merely performing the "actions".
 bitraverse_ :: (Bifoldable t, Applicative f) => (a -> f c) -> (b -> f d) -> t a b -> f ()
 bitraverse_ f g = bifoldr ((*>) . f) ((*>) . g) (pure ())
 {-# INLINE bitraverse_ #-}
 
+-- | As 'bitraverse_', but with the structure as the primary argument.
 bifor_ :: (Bifoldable t, Applicative f) => t a b -> (a -> f c) -> (b -> f d) -> f ()
 bifor_ t f g = bitraverse_ f g t
 {-# INLINE bifor_ #-}
 
+-- | As 'Data.Bitraversable.bimapM', but ignores the results of the functions,
+-- merely performing
+-- the "actions".
 bimapM_:: (Bifoldable t, Monad m) => (a -> m c) -> (b -> m d) -> t a b -> m ()
 bimapM_ f g = bifoldr ((>>) . f) ((>>) . g) (return ())
 {-# INLINE bimapM_ #-}
 
+-- | As 'bimapM_', but with the structure as the primary argument.
 biforM_ :: (Bifoldable t, Monad m) => t a b ->  (a -> m c) -> (b -> m d) -> m ()
 biforM_ t f g = bimapM_ f g t
 {-# INLINE biforM_ #-}
 
+-- | As 'Data.Bitraversable.bisequenceA', but ignores the results of the actions.
 bisequenceA_ :: (Bifoldable t, Applicative f) => t (f a) (f b) -> f ()
 bisequenceA_ = bifoldr (*>) (*>) (pure ())
 {-# INLINE bisequenceA_ #-}
 
+-- | As 'Data.Bitraversable.bisequence', but ignores the results of the actions.
 bisequence_ :: (Bifoldable t, Monad m) => t (m a) (m b) -> m ()
 bisequence_ = bifoldr (>>) (>>) (return ())
 {-# INLINE bisequence_ #-}
 
+-- | Collects the list of elements of a structure in order.
 biList :: Bifoldable t => t a a -> [a]
 biList = bifoldr (:) (:) []
 {-# INLINE biList #-}
 
+-- | Reduces a structure of lists to the concatenation of those lists.
 biconcat :: Bifoldable t => t [a] [a] -> [a]
 biconcat = bifold
 {-# INLINE biconcat #-}
 
+-- | Given a means of mapping the elements of a structure to lists, computes the
+-- concatenation of all such lists in order.
 biconcatMap :: Bifoldable t => (a -> [c]) -> (b -> [c]) -> t a b -> [c]
 biconcatMap = bifoldMap
 {-# INLINE biconcatMap #-}
 
+-- | Determines whether any element of the structure satisfies the appropriate
+-- predicate.
 biany :: Bifoldable t => (a -> Bool) -> (b -> Bool) -> t a b -> Bool
 biany p q = getAny . bifoldMap (Any . p) (Any . q)
 {-# INLINE biany #-}
 
+-- | Determines whether all elements of the structure satisfy the appropriate
+-- predicate.
 biall :: Bifoldable t => (a -> Bool) -> (b -> Bool) -> t a b -> Bool
 biall p q = getAll . bifoldMap (All . p) (All . q)
 {-# INLINE biall #-}
diff --git a/src/Data/Bitraversable.hs b/src/Data/Bitraversable.hs
--- a/src/Data/Bitraversable.hs
+++ b/src/Data/Bitraversable.hs
@@ -25,19 +25,123 @@
 import Data.Monoid
 import Data.Tagged
 
+-- | Minimal complete definition either 'bitraverse' or 'bisequenceA'.
+
+-- | 'Bitraversable' identifies bifunctorial data structures whose elements can
+-- be traversed in order, performing 'Applicative' or 'Monad' actions at each
+-- element, and collecting a result structure with the same shape.
+--
+-- A definition of 'traverse' must satisfy the following laws:
+--
+-- [/naturality/]
+--   @'bitraverse' (t . f) (t . g) ≡ t . 'bitraverse' f g@
+--   for every applicative transformation @t@
+--
+-- [/identity/]
+--   @'bitraverse' 'Identity' 'Identity' ≡ 'Identity'@
+--
+-- [/composition/]
+--   @'Compose' . 'fmap' ('bitraverse' g1 g2) . 'bitraverse' f1 f2
+--     ≡ 'traverse' ('Compose' . 'fmap' g1 . f1) ('Compose' . 'fmap' g2 . f2)@
+--
+-- A definition of 'bisequenceA' must satisfy the following laws:
+--
+-- [/naturality/]
+--   @'bisequenceA' . 'bimap' t t ≡ t . 'bisequenceA'@
+--   for every applicative transformation @t@
+--
+-- [/identity/]
+--   @'bisequenceA' . 'bimap' 'Identity' 'Identity' ≡ 'Identity'@
+--
+-- [/composition/]
+--   @'bisequenceA' . 'bimap' 'Compose' 'Compose'
+--     ≡ 'Compose' . 'fmap' 'bisequenceA' . 'bisequenceA'@
+--
+-- where an /applicative transformation/ is a function
+--
+-- @t :: ('Applicative' f, 'Applicative' g) => f a -> g a@
+--
+-- preserving the 'Applicative' operations:
+--
+-- @
+-- t ('pure' x) = 'pure' x
+-- t (f '<*>' x) = t f '<*>' t x
+-- @
+--
+-- and the identity functor 'Identity' and composition functors 'Compose' are
+-- defined as
+--
+-- > newtype Identity a = Identity { runIdentity :: a }
+-- >
+-- > instance Functor Identity where
+-- >   fmap f (Identity x) = Identity (f x)
+-- >
+-- > instance Applicative Identity where
+-- >   pure = Identity
+-- >   Identity f <*> Identity x = Identity (f x)
+-- >
+-- > newtype Compose f g a = Compose (f (g a))
+-- >
+-- > instance (Functor f, Functor g) => Functor (Compose f g) where
+-- >   fmap f (Compose x) = Compose (fmap (fmap f) x)
+-- >
+-- > instance (Applicative f, Applicative g) => Applicative (Compose f g) where
+-- >   pure = Compose . pure . pure
+-- >   Compose f <*> Compose x = Compose ((<*>) <$> f <*> x)
+--
+-- Some simple examples are 'Either' and '(,)':
+--
+-- > instance Bitraversable Either where
+-- >   bitraverse f _ (Left x) = Left <$> f x
+-- >   bitraverse _ g (Right y) = Right <$> g y
+-- >
+-- > instance Bitraversable (,) where
+-- >   bitraverse f g (x, y) = (,) <$> f x <*> g y
+--
+-- 'Bitraversable' relates to its superclasses in the following ways:
+--
+-- @
+-- 'bimap' f g ≡ 'runIdentity' . 'bitraverse' ('Identity' . f) ('Identity' . g)
+-- 'bifoldMap' f g = 'getConst' . 'bitraverse' ('Const' . f) ('Const' . g)
+-- @
+--
+-- These are available as 'bimapDefault' and 'bifoldMapDefault' respectively.
 class (Bifunctor t, Bifoldable t) => Bitraversable t where
+  -- | Evaluates the relevant functions at each element in the structure, running
+  -- the action, and builds a new structure with the same shape, using the
+  -- elements produced from sequencing the actions.
+  --
+  -- @'bitraverse' f g ≡ 'bisequenceA' . 'bimap' f g@
   bitraverse :: Applicative f => (a -> f c) -> (b -> f d) -> t a b -> f (t c d)
   bitraverse f g = bisequenceA . bimap f g
   {-# INLINE bitraverse #-}
 
+  -- | Sequences all the actions in a structure, building a new structure with the
+  -- same shape using the results of the actions.
+  --
+  -- @'bisequenceA' ≡ 'bitraverse' 'id' 'id'@
   bisequenceA :: Applicative f => t (f a) (f b) -> f (t a b)
   bisequenceA = bitraverse id id
   {-# INLINE bisequenceA #-}
 
+  -- | As 'bitraverse', but uses evidence that @m@ is a 'Monad' rather than an
+  -- 'Applicative'.
+  --
+  -- @
+  -- 'bimapM' f g ≡ 'bisequence' . 'bimap' f g
+  -- 'bimapM' f g ≡ 'unwrapMonad' . 'bitraverse' ('WrapMonad' . f) ('WrapMonad' . g)
+  -- @
   bimapM :: Monad m => (a -> m c) -> (b -> m d) -> t a b -> m (t c d)
   bimapM f g = unwrapMonad . bitraverse (WrapMonad . f) (WrapMonad . g)
   {-# INLINE bimapM #-}
 
+  -- | As 'bisequenceA', but uses evidence that @m@ is a 'Monad' rather than an
+  -- 'Applicative'.
+  --
+  -- @
+  -- 'bisequence' ≡ 'bimapM' 'id' 'id'
+  -- 'bisequence' ≡ 'unwrapMonad' . 'bisequenceA' . 'bimap' 'WrapMonad' 'WrapMonad'
+  -- @
   bisequence :: Monad m => t (m a) (m b) -> m (t a b)
   bisequence = bimapM id id
   {-# INLINE bisequence #-}
@@ -71,10 +175,12 @@
   bitraverse _ g (Tagged b) = Tagged <$> g b
   {-# INLINE bitraverse #-}
 
+-- | 'bifor' is 'bitraverse' with the structure as the first argument.
 bifor :: (Bitraversable t, Applicative f) => t a b -> (a -> f c) -> (b -> f d) -> f (t c d)
 bifor t f g = bitraverse f g t
 {-# INLINE bifor #-}
 
+-- | 'biforM' is 'bimapM' with the structure as the first argument.
 biforM :: (Bitraversable t, Monad m) =>  t a b -> (a -> m c) -> (b -> m d) -> m (t c d)
 biforM t f g = bimapM f g t
 {-# INLINE biforM #-}
@@ -96,6 +202,8 @@
     in (s'', f v)
   {-# INLINE (<*>) #-}
 
+-- | Traverses a structure from left to right, threading a state of type @a@
+-- and using the given actions to compute new elements for the structure.
 bimapAccumL :: Bitraversable t => (a -> b -> (a, c)) -> (a -> d -> (a, e)) -> a -> t b d -> (a, t c e)
 bimapAccumL f g s t = runStateL (bitraverse (StateL . flip f) (StateL . flip g) t) s
 {-# INLINE bimapAccumL #-}
@@ -117,6 +225,8 @@
     in (s'', f v)
   {-# INLINE (<*>) #-}
 
+-- | Traverses a structure from right to left, threading a state of type @a@
+-- and using the given actions to compute new elements for the structure.
 bimapAccumR :: Bitraversable t => (a -> b -> (a, c)) -> (a -> d -> (a, e)) -> a -> t b d -> (a, t c e)
 bimapAccumR f g s t = runStateR (bitraverse (StateR . flip f) (StateR . flip g) t) s
 {-# INLINE bimapAccumR #-}
@@ -133,10 +243,12 @@
   Id f <*> Id x = Id (f x)
   {-# INLINE (<*>) #-}
 
+-- | A default definition of 'bimap' in terms of the 'Bitraversable' operations.
 bimapDefault :: Bitraversable t => (a -> b) -> (c -> d) -> t a c -> t b d
 bimapDefault f g = getId . bitraverse (Id . f) (Id . g)
 {-# INLINE bimapDefault #-}
 
+-- | A default definition of 'bifoldMap' in terms of the 'Bitraversable' operations.
 bifoldMapDefault :: (Bitraversable t, Monoid m) => (a -> m) -> (b -> m) -> t a b -> m
 bifoldMapDefault f g = getConst . bitraverse (Const . f) (Const . g)
 {-# INLINE bifoldMapDefault #-}
