diff --git a/ip.cabal b/ip.cabal
--- a/ip.cabal
+++ b/ip.cabal
@@ -1,7 +1,6 @@
 name:                ip
-version:             0.8.4
+version:             0.8.5
 synopsis:            Library for IP and MAC addresses
-description:         Please see README.md
 homepage:            https://github.com/andrewthad/haskell-ip#readme
 license:             BSD3
 license-file:        LICENSE
@@ -11,6 +10,30 @@
 category:            web
 build-type:          Simple
 cabal-version:       >=1.10
+description:
+  The `ip` package provides types and functions for dealing with
+  IPv4 addresses, CIDR blocks, and MAC addresses. We provide instances
+  for typeclasses found in commonly used packages like `aeson`, `vector`,
+  and `hashable`. We also provide `Parser`s for working with attoparsec.
+  .
+  Notably, this package does not overload functions by introducing any
+  typeclasses of its own. Neither does it prefix functions with the name
+  of the type that they work on. Instead, functions of the same name are
+  exported by several different modules, and it is expected that end users
+  disambiguate by imported these modules qualified. For example,
+  `Data.IPv4.Text` and `Data.IPv4.ByteString.Char8` have nearly identical
+  export lists.
+  .
+  The only module intended to be imported unqualified is `Net.Types`. The
+  types in this package should not conflict with the types in
+  any other commonly used packages.
+  .
+  The following packages are intended to be used with this package:
+  .
+  * `yesod-ip`: Provides orphan instances needed to work with yesod and
+    persistent. Also, provides a `yesod-form` helper.
+  * `impure-containers`: Provides a trie that can be used for looking
+    up which subnet an IP address belongs in.
 
 library
   hs-source-dirs:      src
diff --git a/src/Net/IPv4.hs b/src/Net/IPv4.hs
--- a/src/Net/IPv4.hs
+++ b/src/Net/IPv4.hs
@@ -90,7 +90,7 @@
 loopback :: IPv4
 loopback = fromOctets 127 0 0 1
 
--- | The broadcast IP address: @127.0.0.1@
+-- | The broadcast IP address: @255.255.255.255@
 broadcast :: IPv4
 broadcast = fromOctets 255 255 255 255
 
diff --git a/src/Net/IPv4/Range.hs b/src/Net/IPv4/Range.hs
--- a/src/Net/IPv4/Range.hs
+++ b/src/Net/IPv4/Range.hs
@@ -5,6 +5,9 @@
   , member
   , lowerInclusive
   , upperInclusive
+    -- * Conversion to IPv4
+  , toList
+  , toGenerator
     -- * Private Ranges
   , private24
   , private20
@@ -16,6 +19,8 @@
 
 import Net.Types (IPv4(..),IPv4Range(..))
 import Data.Bits ((.&.),(.|.),shiftR,shiftL,complement)
+import Data.Coerce (coerce)
+import Control.Monad
 import qualified Net.Internal as Internal
 import qualified Net.IPv4     as IPv4
 import qualified Data.Text.IO as Text
@@ -87,6 +92,25 @@
   let theInvertedMask = shiftR 0xffffffff (fromIntegral len)
       theMask = complement theInvertedMask
    in IPv4 ((w .&. theMask) .|. theInvertedMask)
+
+-- | Convert an 'IPv4Range' into a list of the 'IPv4' addresses that
+--   are in it.
+-- >>> let r = IPv4Range (fromOctets 192 168 1 8) 30
+-- >>> mapM_ I.print (toList r)
+-- 192.168.1.8
+-- 192.168.1.9
+-- 192.168.1.10
+-- 192.168.1.11
+
+toList :: IPv4Range -> [IPv4]
+toList (IPv4Range (IPv4 ip) len) = 
+  let totalAddrs = Internal.countAddrs len
+   in coerce (Internal.wordSuccessors totalAddrs ip)
+
+toGenerator :: MonadPlus m => IPv4Range -> m IPv4
+toGenerator (IPv4Range (IPv4 ip) len) =  
+  let totalAddrs = Internal.countAddrs len
+   in Internal.wordSuccessorsM IPv4 totalAddrs ip
 
 -- | The RFC1918 24-bit block. Subnet mask: @10.0.0.0/8@
 private24 :: IPv4Range
diff --git a/src/Net/Internal.hs b/src/Net/Internal.hs
--- a/src/Net/Internal.hs
+++ b/src/Net/Internal.hs
@@ -1,8 +1,10 @@
+{-# LANGUAGE BangPatterns #-}
+
 module Net.Internal where
 
 import Data.Monoid ((<>))
 import Data.Word
-import Data.Bits ((.&.),(.|.),shiftR,shiftL,complement)
+import Data.Bits ((.&.),(.|.),shiftR,shiftL,shift,complement)
 import Control.Monad.ST
 import Data.Text.Internal (Text(..))
 import Data.ByteString (ByteString)
@@ -231,6 +233,30 @@
   .|. shiftL c 8
   .|. d
     )
+
+-- | Given the size of the mask, return the
+--   total number of ips in the subnet. This
+--   only works for IPv4 addresses because 
+--   an IPv6 subnet can have up to 2^128 
+--   addresses.
+countAddrs :: Word8 -> Word64
+countAddrs w = 
+  let amountToShift = if w > 32
+        then 0
+        else 32 - fromIntegral w
+   in shift 1 amountToShift
+
+wordSuccessors :: Word64 -> Word32 -> [Word32]
+wordSuccessors !w !a = if w > 0
+  then a : wordSuccessors (w - 1) (a + 1)
+  else []
+
+wordSuccessorsM :: MonadPlus m => (Word32 -> a) -> Word64 -> Word32 -> m a
+wordSuccessorsM f = go where
+  go !w !a = if w > 0
+    then mplus (return (f a)) (go (w - 1) (a + 1))
+    else mzero
+{-# INLINE wordSuccessorsM #-}
 
 mask :: Word8 -> Word32
 mask = complement . shiftR 0xffffffff . fromIntegral
diff --git a/src/Net/Types.hs b/src/Net/Types.hs
--- a/src/Net/Types.hs
+++ b/src/Net/Types.hs
@@ -27,7 +27,7 @@
 import qualified Data.Vector.Unboxed.Mutable    as MUVector
 import qualified Data.Vector.Primitive.Mutable  as MPVector
 import Data.Primitive.Types (Prim)
-import Data.Bits ((.|.),shiftL)
+import Data.Bits (Bits,(.|.),shiftL)
 import Data.Coerce (coerce)
 import Control.Monad
 import Data.Word
@@ -38,7 +38,7 @@
 
 -- | A 32-bit Internet Protocol address.
 newtype IPv4 = IPv4 { getIPv4 :: Word32 }
-  deriving (Eq,Ord,Show,Read,Enum,Bounded,Hashable,Generic,Prim)
+  deriving (Eq,Ord,Show,Read,Enum,Bounded,Hashable,Generic,Prim,Bits)
 
 -- | The length should be between 0 and 32. These bounds are inclusive.
 --   This expectation is not in any way enforced by this library because
