diff --git a/AUTHORS.md b/AUTHORS.md
new file mode 100644
--- /dev/null
+++ b/AUTHORS.md
@@ -0,0 +1,7 @@
+The following people have participated in creating this library, either
+by directly contributing code, by providing thoughtful input in
+discussions about the library design, or by doing anything else that
+helps this library move forwards.
+
+- [Danny Navarro](mailto:j@dannynavarro.net) [@jdnavarro](https://github.com/jdnavarro)
+- [Roman Cheplyaka](mailto:roma@ro-che.info) [@feuerbach](https://github.com/feuerbach)
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,15 @@
 CHANGELOG](http://keepachangelog.com/). This project adheres to [Semantic
 Versioning](http://semver.org/).
 
+## [0.3] - 2015-5-25
+### Added
+- Serial instance for `Map`.
+- `zipLogic` for *zipping* instances. Thanks to Roman Cheplyaka
+  [@feuerbach](https://github.com/feuerbach).
+
+### Fixed
+- Compatibility with GHC < 7.10.
+
 ## [0.2] - 2015-4-28
 ### Changed
 - General renaming to, hopefully, make functions more clear.
@@ -16,5 +25,6 @@
 - Initial set of utilities for creating `ByteString` and `Text` `Series`.
 - `Serial` `ByteString` and `Text` instances.
 
+[0.3]: https://github.com/jdnavarro/smallcheck-series/compare/v0.2...v0.3
 [0.2]: https://github.com/jdnavarro/smallcheck-series/compare/v0.1...v0.2
 [0.1]: https://github.com/jdnavarro/smallcheck-series/compare/49b5b0...v0.1
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -2,5 +2,5 @@
 
 [![Hackage Version](https://img.shields.io/hackage/v/smallcheck-series.svg)](https://hackage.haskell.org/package/smallcheck-series) [![Build Status](https://img.shields.io/travis/jdnavarro/smallcheck-series.svg)](https://travis-ci.org/jdnavarro/smallcheck-series)
 
-Utilities for creating `Series` and orphan instances for frequently
-used types coming with GHC core libraries.
+Orphan `Serial` instances and utilities to create and manipulate `Series`
+for common types.
diff --git a/Test/SmallCheck/Series/ByteString.hs b/Test/SmallCheck/Series/ByteString.hs
--- a/Test/SmallCheck/Series/ByteString.hs
+++ b/Test/SmallCheck/Series/ByteString.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-|
 Following the convention from "Data.ByteString", this module is intended to be
 imported @qualified@. For example:
@@ -18,13 +19,16 @@
   , jack
   ) where
 
-import Data.Char (ord)
-import Data.List (inits)
 import Data.Word (Word8)
-import Data.ByteString (ByteString, pack)
-import qualified Data.ByteString.Char8 as B8 (pack)
+#if !MIN_VERSION_base(4,8,0)
+import Control.Applicative ((<$>))
+#endif
+import Data.ByteString (ByteString)
+import qualified Data.ByteString.Lazy as L (toStrict)
 import Test.SmallCheck.Series
 
+import qualified Test.SmallCheck.Series.ByteString.Lazy as L.Series
+
 -- | A 'Data.ByteString.ByteString' 'Series' that grows by replicating
 --   the @97@ 'Word8', which encodes the 'a' 'Char' in @ASCII@.
 --
@@ -33,7 +37,7 @@
 --
 -- Use this when you don't care about the 'Word8' inside 'Data.ByteString.ByteString'.
 replicateA :: Series m ByteString
-replicateA = replicateW8 97
+replicateA = L.toStrict <$> L.Series.replicateA
 
 -- | A 'Data.ByteString.ByteString' 'Series' that grows by replicating
 --   the @0@ 'Word8'.
@@ -41,7 +45,7 @@
 -- >>> list 4 replicate0
 -- ["","\NUL","\NUL\NUL","\NUL\NUL\NUL","\NUL\NUL\NUL\NUL"]
 replicate0 :: Series m ByteString
-replicate0 = replicateW8 0
+replicate0 = L.toStrict <$> L.Series.replicate0
 
 -- | A 'Data.ByteString.ByteString' 'Series' that grows by replicating
 --   the given 'Word8'.
@@ -49,8 +53,7 @@
 -- >>> list 4 $ replicateW8 64
 -- ["","@","@@","@@@","@@@@"]
 replicateW8 :: Word8 -> Series m ByteString
-replicateW8 b =
-    generate $ \d -> fmap pack . inits $ replicate d b
+replicateW8 = fmap L.toStrict . L.Series.replicateW8
 
 -- | A 'Data.ByteString.ByteString' 'Series' that grows by enumerating
 --   every 'Word8'.
@@ -58,7 +61,7 @@
 -- >>> list 4 enumW8s
 -- ["","\NUL","\NUL\SOH","\NUL\SOH\STX","\NUL\SOH\STX\ETX"]
 enumW8s :: Series m ByteString
-enumW8s = enumList [0..255]
+enumW8s = L.toStrict <$> L.Series.enumW8s
 
 -- | A 'Data.ByteString.ByteString' 'Series' that grows by enumerating
 --   the 'Word8's which encode the latin alphabet in @ASCII@.
@@ -66,15 +69,16 @@
 -- >>> list 4 enumAlphabet
 -- ["","a","ab","abc","abcd"]
 enumAlphabet :: Series m ByteString
-enumAlphabet = enumList $ fmap (fromIntegral . ord) ['a'..'z']
+enumAlphabet = L.toStrict <$> L.Series.enumAlphabet
 
 -- | A 'Data.ByteString.ByteString' 'Series' that grows by enumerating
 --   every 'Word8' in the given list.
 --
+-- >>> import Data.Char (ord)
 -- >>> list 4 . enumList $ fmap (fromIntegral . ord) "abc"
 -- ["","a","ab","abc"]
 enumList  :: [Word8] -> Series m ByteString
-enumList cs = generate $ \d -> fmap pack . inits $ take d cs
+enumList = fmap L.toStrict . L.Series.enumList
 
 -- | A 'Data.ByteString.ByteString' 'Series' that grows with @ASCII@
 --   dummy English words encoded in @ASCII@.
@@ -87,6 +91,4 @@
 -- >>> last s
 -- "All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy."
 jack :: Series m ByteString
-jack = generate $ \d ->
-    fmap (B8.pack . unwords) . inits . take d . cycle . words $
-        "All work and no play makes Jack a dull boy."
+jack = L.toStrict <$> L.Series.jack
diff --git a/Test/SmallCheck/Series/Instances.hs b/Test/SmallCheck/Series/Instances.hs
--- a/Test/SmallCheck/Series/Instances.hs
+++ b/Test/SmallCheck/Series/Instances.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
@@ -19,12 +20,17 @@
 -}
 module Test.SmallCheck.Series.Instances () where
 
+#if !MIN_VERSION_base(4,8,0)
+import Control.Applicative ((<$>))
+#endif
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as BL
 import qualified Data.Text as T
 import qualified Data.Text.Lazy as TL
+import qualified Data.Map as Map
 import Test.SmallCheck.Series
 
+
 import Test.SmallCheck.Series.ByteString as Series.ByteString
 import Test.SmallCheck.Series.ByteString.Lazy as Series.ByteString.Lazy
 import Test.SmallCheck.Series.Text as Series.Text
@@ -41,3 +47,6 @@
 
 instance Monad m => Serial m TL.Text where
     series = Series.Text.Lazy.replicateA
+
+instance (Serial m k, Serial m v) => Serial m (Map.Map k v) where
+    series = Map.singleton <$> series <~> series
diff --git a/Test/SmallCheck/Series/Text.hs b/Test/SmallCheck/Series/Text.hs
--- a/Test/SmallCheck/Series/Text.hs
+++ b/Test/SmallCheck/Series/Text.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-|
 Following the convention from "Data.Text", this module is intended to be
 imported @qualified@. For example:
@@ -20,10 +21,15 @@
   , enumNonBmp
   ) where
 
-import Data.List (inits)
-import Data.Text (Text, pack)
+#if !MIN_VERSION_base(4,8,0)
+import Control.Applicative ((<$>))
+#endif
+import Data.Text (Text)
+import qualified Data.Text.Lazy as L (toStrict)
 import Test.SmallCheck.Series
 
+import qualified Test.SmallCheck.Series.Text.Lazy as L.Series
+
 -- | A 'Data.Text.Text' 'Series' that grows by replicating the @a@ 'Char'.
 --
 -- >>> list 4 replicateA
@@ -31,35 +37,35 @@
 --
 -- Use this when you don't care about the 'Char's inside 'Data.Text.Text'.
 replicateA :: Series m Text
-replicateA = replicateChar 'a'
+replicateA = L.toStrict <$> L.Series.replicateA
 
 -- | A 'Data.Text.Text' 'Series' that grows by replicating the @NUL@ 'Char'.
 --
 -- >>> list 4 replicateNull
 -- ["","\NUL","\NUL\NUL","\NUL\NUL\NUL","\NUL\NUL\NUL\NUL"]
 replicateNull :: Series m Text
-replicateNull = replicateChar '\0'
+replicateNull = L.toStrict <$> L.Series.replicateNull
 
 -- | A 'Data.Text.Text' 'Series' that grows by replicating the given 'Char'.
 --
 -- >>> list 4 $ replicateChar '☃'
 -- ["","\9731","\9731\9731","\9731\9731\9731","\9731\9731\9731\9731"]
 replicateChar :: Char -> Series m Text
-replicateChar c = generate $ \d -> fmap pack . inits $ replicate d c
+replicateChar = fmap L.toStrict . L.Series.replicateChar
 
 -- | A 'Data.Text.Text' 'Series' that grows by enumerating the latin alphabet.
 --
 -- >>> list 4 enumAlphabet
 -- ["","a","ab","abc","abcd"]
 enumAlphabet :: Series m Text
-enumAlphabet = enumString ['a'..'z']
+enumAlphabet = L.toStrict <$> L.Series.enumAlphabet
 
 -- | A 'Data.Text.Text' 'Series' that grows by enumerating every 'Char'.
 --
 -- >>> list 4 enumChars
 -- ["","\NUL","\NUL\SOH","\NUL\SOH\STX","\NUL\SOH\STX\ETX"]
 enumChars :: Series m Text
-enumChars = enumString ['\0'..]
+enumChars = L.toStrict <$> L.Series.enumChars
 
 -- | A 'Data.Text.Text' 'Series' that grows by enumerating every 'Char' in the
 --   given 'String'. Notice that the 'String' can be infinite.
@@ -67,7 +73,7 @@
 -- >>> list 5 $ enumString "xyz"
 -- ["","x","xy","xyz"]
 enumString :: String -> Series m Text
-enumString cs = generate $ \d -> fmap pack . inits $ take d cs
+enumString = fmap L.toStrict . L.Series.enumString
 
 -- | A 'Data.Text.Text' 'Series' that grows with English words.
 --
@@ -79,9 +85,7 @@
 -- >>> last s
 -- "All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy."
 jack :: Series m Text
-jack = generate $ \d ->
-    fmap (pack . unwords) . inits . take d . cycle . words $
-        "All work and no play makes Jack a dull boy."
+jack = L.toStrict <$> L.Series.jack
 
 -- | A 'Data.Text.Text' 'Series' that grows with the first character of each
 --   <https://en.wikipedia.org/wiki/Plane_(Unicode) Unicode plane>.
diff --git a/Test/SmallCheck/Series/Utils.hs b/Test/SmallCheck/Series/Utils.hs
new file mode 100644
--- /dev/null
+++ b/Test/SmallCheck/Series/Utils.hs
@@ -0,0 +1,50 @@
+module Test.SmallCheck.Series.Utils
+  (
+  -- * Zipping
+    zipLogic
+  , zipLogic3
+  ) where
+
+import Control.Monad.Logic ((<=<), MonadLogic(msplit), lift, mplus, mzero)
+import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
+
+-- $setup
+-- >>> import Data.Char
+-- >>> import Data.Functor.Identity
+-- >>> import Data.Text (Text)
+-- >>> import Test.SmallCheck.Series
+-- >>> import Test.SmallCheck.Series.Instances
+
+-- | /One-to-One/ zipping of 2 'MonadLogic' instances. You can use for
+--   'Test.SmallCheck.Series' like this:
+--
+-- >>> list 2 $ (series :: Series Identity Char) `zipLogic` (series :: Series Identity Int)
+-- [('a',0),('b',1),('c',-1)]
+--
+-- Notice the difference with 'Test.SmallCheck.Series.><':
+--
+-- >>> list 2 $ (series :: Series Identity Char) >< (series :: Series Identity Int)
+-- [('a',0),('b',0),('a',1),('c',0),('a',-1),...,('b',-2),('c',-2)]
+
+-- Thanks to Roman Cheplyaka: https://groups.google.com/d/msg/haskell-tasty/k0dXCx9EBsc/XYkCTjYKqswJ
+zipLogic :: MonadLogic m => m a -> m b -> m (a, b)
+zipLogic gx gy =
+  maybe mzero return <=< runMaybeT $ do
+    (x, rx) <- MaybeT (msplit gx)
+    (y, ry) <- MaybeT (msplit gy)
+    lift $ return (x, y) `mplus` zipLogic rx ry
+
+-- | /One-to-One/ zipping of 3 'MonadLogic' instances. You can use for
+--   'Test.SmallCheck.Series' like this:
+--
+-- >>> list 2 $ zipLogic3 (series :: Series Identity Char) (series :: Series Identity Int) (series :: Series Identity Text)
+-- [('a',0,""),('b',1,"a"),('c',-1,"aa")]
+
+-- Thanks to Roman Cheplyaka: https://groups.google.com/d/msg/haskell-tasty/k0dXCx9EBsc/XYkCTjYKqswJ
+zipLogic3 :: MonadLogic m => m a -> m b -> m c -> m (a, b, c)
+zipLogic3 gx gy gz =
+  maybe mzero return <=< runMaybeT $ do
+    (x, rx) <- MaybeT (msplit gx)
+    (y, ry) <- MaybeT (msplit gy)
+    (z, rz) <- MaybeT (msplit gz)
+    lift $ return (x, y, z) `mplus` zipLogic3 rx ry rz
diff --git a/smallcheck-series.cabal b/smallcheck-series.cabal
--- a/smallcheck-series.cabal
+++ b/smallcheck-series.cabal
@@ -1,9 +1,9 @@
 name:                smallcheck-series
-version:             0.2
-synopsis:            Extra SmallCheck series
+version:             0.3
+synopsis:            Extra SmallCheck series and utilities
 description:
-  Orphan @Serial@ instances and utilities to create custom @Series@ for
-  common types.
+  Orphan @Serial@ instances and utilities to create and manipulate
+  @Series@ for common types.
 homepage:            https://github.com/jdnavarro/smallcheck-series
 bug-reports:         https://github.com/jdnavarro/smallcheck-series/issues
 license:             BSD3
@@ -12,26 +12,29 @@
 maintainer:          j@dannynavarro.net
 category:            Testing
 build-type:          Simple
-extra-source-files:  README.md CHANGELOG.md
+extra-source-files:  README.md CHANGELOG.md AUTHORS.md
 cabal-version:       >=1.10
 
 source-repository head
   type: git
   location: git://github.com/jdnavarro/smallcheck-series.git
 
-
 library
+  default-language:    Haskell2010
+  ghc-options:         -Wall
   exposed-modules:     Test.SmallCheck.Series.ByteString
                        Test.SmallCheck.Series.ByteString.Lazy
                        Test.SmallCheck.Series.Instances
                        Test.SmallCheck.Series.Text
                        Test.SmallCheck.Series.Text.Lazy
+                       Test.SmallCheck.Series.Utils
   build-depends:       base >=4.6 && <4.9,
-                       bytestring >= 0.10.0,
-                       text >= 0.11.3,
-                       smallcheck >= 1.1
-  default-language:    Haskell2010
-  ghc-options:         -Wall
+                       bytestring >=0.10.0,
+                       containers >=0.5.0.0,
+                       text >=0.11.3,
+                       transformers >=0.3.0.0,
+                       logict >=0.6.0.2,
+                       smallcheck >=1.1
 
 test-suite doctests
   default-language:    Haskell2010
@@ -39,6 +42,6 @@
   hs-source-dirs:      tests
   main-is:             doctests.hs
   ghc-options:         -Wall -threaded
-  build-depends:       base >= 4.6 && <4.9,
-                       Glob >= 0.7.5,
-                       doctest >= 0.9.10
+  build-depends:       base >=4.6 && <4.9,
+                       Glob >=0.7.5,
+                       doctest >=0.9.10
