diff --git a/list-transformer.cabal b/list-transformer.cabal
--- a/list-transformer.cabal
+++ b/list-transformer.cabal
@@ -1,5 +1,5 @@
 name:                list-transformer
-version:             1.0.0
+version:             1.0.1
 synopsis:            List monad transformer
 description:         This library provides a list monad transformer that
                      enriches lists with effects and streams efficiently in
@@ -25,3 +25,13 @@
   build-depends:       base >= 4.5 && < 5
                      , mtl >= 2.1 && < 2.3
   ghc-options:         -Wall
+
+test-suite doctest
+  type: exitcode-stdio-1.0
+  main-is: DocTest.hs
+  hs-source-dirs: test
+  build-depends:
+      base
+    , doctest
+    , list-transformer
+  default-language: Haskell2010
diff --git a/src/List/Transformer.hs b/src/List/Transformer.hs
--- a/src/List/Transformer.hs
+++ b/src/List/Transformer.hs
@@ -11,8 +11,8 @@
 
 > -- Every `ListT` begins with an outermost effect (the `m`)
 > newtype ListT m a = ListT { next :: m (Step m a) }
-> 
 >
+>
 > -- The return value of that effect is either
 > -- * Cons: a new list element followed by the rest of the list
 > -- * Nil : an empty list
@@ -48,7 +48,7 @@
 
     Combining @stdin@ and @stdout@ forwards lines one-by-one from standard input
     to standard output:
-    
+
 > main :: IO ()
 > main = stdout stdin
 
@@ -79,7 +79,7 @@
     You can even use list comprehension syntax if you enable the
     @MonadComprehensions@ language extension:
 
-> stdout strings = runListT [ r | string <- strings, r <- liftIO (putStrLn str) ]
+> stdout strings = runListT [ r | str <- strings, r <- liftIO (putStrLn str) ]
 
     The most important operations that you should familiarize yourself with are:
 
@@ -103,7 +103,7 @@
 
 > (>>=) :: ListT IO a -> (a -> ListT IO b) -> ListT IO b
 
-    For example, suppose you want to a build a `ListT` with three elements and
+    For example, suppose you want to build a `ListT` with three elements and
     no effects.  You could just write:
 
 > pure 1 <|> pure 2 <|> pure 3 :: ListT IO Int
@@ -175,6 +175,10 @@
     , fold
     , foldM
     , select
+    , take
+    , drop
+    , unfold
+    , zip
 
       -- * Step
     , Step(..)
@@ -199,9 +203,13 @@
 import Control.Monad.State.Class (MonadState(..))
 import Control.Monad.Reader.Class (MonadReader(..))
 import Control.Monad.Trans (MonadTrans(..), MonadIO(..))
+import Prelude hiding (drop, take, zip)
 
 import qualified Data.Foldable
 
+-- $setup
+-- >>> :set -XNoMonomorphismRestriction
+
 {-| This is like a list except that you can interleave effects between each list
     element.  For example:
 
@@ -419,6 +427,78 @@
 select = Data.Foldable.foldr cons empty
   where
     cons x xs = pure x <|> xs
+
+
+-- | @take n xs@ takes @n@ elements from the head of @xs@.
+--
+-- >>> let list xs = do x <- select xs; liftIO (print (show x)); return x
+-- >>> let sum = fold (+) 0 id
+-- >>> sum (take 2 (list [5,4,3,2,1]))
+-- "5"
+-- "4"
+-- 9
+take :: Monad m => Int -> ListT m a -> ListT m a
+take n l
+    | n <= 0    = empty
+    | otherwise = ListT (do
+        s <- next l
+        case s of
+            Cons a l' -> return (Cons a (take (n-1) l'))
+            Nil       -> return Nil)
+
+-- | @drop n xs@ drops @n@ elements from the head of @xs@, but still runs their
+-- effects.
+--
+-- >>> let list xs = do x <- select xs; liftIO (print (show x)); return x
+-- >>> let sum = fold (+) 0 id
+-- >>> sum (drop 2 (list [5,4,3,2,1]))
+-- "5"
+-- "4"
+-- "3"
+-- "2"
+-- "1"
+-- 6
+drop :: Monad m => Int -> ListT m a -> ListT m a
+drop n l
+    | n <= 0    = l
+    | otherwise = ListT (do
+        s <- next l
+        case s of
+            Cons _ l' -> next (drop (n-1) l')
+            Nil       -> return Nil)
+
+-- | @unfold step seed@ generates a 'ListT' from a @step@ function and an
+-- initial @seed@.
+unfold :: Monad m => (b -> m (Maybe (a, b))) -> b -> ListT m a
+unfold step = loop
+  where
+    loop seed = ListT (do
+        mx <- step seed
+        case mx of
+            Just (x, seed') -> return (Cons x (loop seed'))
+            Nothing         -> return Nil)
+
+-- | @zip xs ys@ zips two 'ListT' together, running the effects of each before
+-- possibly recursing. Notice in the example below, @4@ is output even though
+-- it has no corresponding element in the second list.
+--
+-- >>> let list xs = do x <- select xs; liftIO (print (show x)); return x
+-- >>> runListT (zip (list [1,2,3,4,5]) (list [6,7,8]))
+-- "1"
+-- "6"
+-- "2"
+-- "7"
+-- "3"
+-- "8"
+-- "4"
+zip :: Monad m => ListT m a -> ListT m b -> ListT m (a, b)
+zip xs ys = ListT (do
+    sx <- next xs
+    sy <- next ys
+    case (sx, sy) of
+        (Cons x xs', Cons y ys') -> return (Cons (x, y) (zip xs' ys'))
+        _                        -> return Nil)
+
 
 {-| Pattern match on this type when you loop explicitly over a `ListT` using
     `next`.  For example:
diff --git a/test/DocTest.hs b/test/DocTest.hs
new file mode 100644
--- /dev/null
+++ b/test/DocTest.hs
@@ -0,0 +1,9 @@
+module Main where
+
+import Test.DocTest
+
+main :: IO ()
+main = doctest
+  [ "-XCPP"
+  , "src/List/Transformer.hs"
+  ]
