diff --git a/src/Data/Splittable.hs b/src/Data/Splittable.hs
deleted file mode 100644
--- a/src/Data/Splittable.hs
+++ /dev/null
@@ -1,84 +0,0 @@
-{-# LANGUAGE ScopedTypeVariables #-}
-module Data.Splittable (
-    Splittable(..)
-  
-  , boundedEnum
-  
-  , Left(..)
-  , Right(..)
-  
-  ) where 
-
-import qualified System.Random as R
-import Data.List (mapAccumR)
-import Data.Monoid (Dual(..))
-
--- | Splittable datatypes are datatypes that can be used as seeds for unfolds.
-class Splittable s where
-  -- | @split n s@ splits the seed @s@ in @n@ seeds. 
-  split  :: Int -> s -> [s]
-  -- | @choose fs s@ uses part of the seed @s@ to choose a function from the list @fs@,
-  -- and passes the remainder to that function.
-  choose :: [s -> x] -> s -> x
-  -- | Convert the seed value to an @int@.
-  getInt :: s -> Int
-
--- | If a datatype is bounded and enumerable, we can use 'getInt' to produce a value from a seed.
-boundedEnum :: forall s a. (Splittable s, Bounded a, Enum a) => s -> a
-boundedEnum s = toEnum $ (getInt s `mod'` (1 + ub - lb)) + lb
-  where 
-    lb = fromEnum (minBound :: a)
-    ub = fromEnum (maxBound :: a)
-    n `mod'` 0 = n - lb
-    n `mod'` m = n `mod` m 
-
-data Left = L
--- | Always choose the first item.
-instance Splittable Left where
-  split = replicate
-  choose fs = head fs
-  getInt L = 0
-
-data Right = R
--- | Always choose the last item.
-instance Splittable Right where
-  split = replicate
-  choose fs = last fs
-  getInt R = 0
-
--- | Choose randomly
-instance Splittable R.StdGen where
-  split 0 _ = []
-  split 1 s = [s]
-  split n s = let (s1, s2) = R.split s in s1 : split (n - 1) s2 
-  choose fs s = let (n, s') = R.next s in fs !! (n `mod` length fs) $ s'
-  getInt = fst . R.next
-
--- | The 'Integer' instance uses modulo to choose, and splits breadth-first by 
--- distributing bits in a round-robin fashion.
-instance Splittable Integer where
-  split n t = split' 1 (t, replicate n 0)
-    where
-      split' _ (0, l) = l
-      split' p (s, l) = split' (p * 2) $ mapAccumR (\s' i -> let (s'', b) = s' `divMod` 2 in (s'', i + b * p)) s l
-  choose fs s = let (s', n) = s `divMod` toInteger (length fs) in fs !! fromInteger n $ s'
-  getInt = fromInteger
-
--- | The @(a, b)@ instance uses only @a@ for 'choose' and @b@ for 'getInt'.
-instance (Splittable a, Splittable b) => Splittable (a, b) where
-  split n (a, b) = zip (split n a) (split n b)
-  choose = uncurry . choose . map curry
-  getInt (_, b) = getInt b
-
--- | Choose between 2 ways to split and choose.
-instance (Splittable a, Splittable b) => Splittable (Either a b) where
-  split n   = either (map Left . split n) (map Right . split n)
-  choose fs = either (choose (map (. Left) fs)) (choose (map (. Right) fs))
-  getInt (Left a) = getInt a * 2
-  getInt (Right a) = getInt a * 2 + 1
-
--- | Reverse the split output and the choose input.
-instance Splittable s => Splittable (Dual s) where
-  split n = map Dual . reverse . split n . getDual
-  choose fs = choose (map (. Dual) $ reverse fs) . getDual
-  getInt = negate . getInt . getDual
diff --git a/src/Data/Unfoldable.hs b/src/Data/Unfoldable.hs
--- a/src/Data/Unfoldable.hs
+++ b/src/Data/Unfoldable.hs
@@ -1,27 +1,34 @@
-module Data.Unfoldable (
-
-    Unfoldable(..)
-
+module Data.Unfoldable 
+  (
+    Unfolder(..)
+  
+  , Unfoldable(..)
+  , unfold_
+  , unfoldBF
+  , unfoldBF_
+  
   -- ** Specific unfolds
-  , unfold
   , leftMost
   , rightMost
-
-  -- ** Helper functions
-  , spread
-  , to
-
-  ) where
+  , allDepthFirst
+  , allBreadthFirst
+  , randomDefault
+  , fromList
+  
+  ) 
+  where
     
 import Control.Applicative
-import Control.Monad.Trans.State
-import Data.Splittable
-import Data.Monoid (Dual(..))
+import Control.Monad
+import Data.Unfolder
 import Data.Functor.Compose
 import Data.Functor.Constant
 import Data.Functor.Identity
 import Data.Functor.Product
 import Data.Functor.Reverse
+import Control.Monad.Trans.State
+import qualified System.Random as R
+import Data.Maybe (listToMaybe)
 
 -- | Data structures that can be unfolded.
 --
@@ -32,72 +39,94 @@
 -- a suitable instance would be
 --
 -- > instance Unfoldable Tree where
--- >   unfoldMap f = choose
--- >     [ spread $ pure Empty
--- >     , spread $ Leaf <$> to f
--- >     , spread $ Node <$> to (unfoldMap f) <*> to f <*> to (unfoldMap f)
+-- >   unfold fa = choose
+-- >     [ pure Empty
+-- >     , Leaf <$> fa
+-- >     , Node <$> unfold fa <*> fa <*> unfold fa
 -- >     ]
 --
--- i.e. it follows closely the instance for 'Traversable', with the addition of 'choose', 'spread' and 'to'.
--- 
--- The instance can be simplified to:
---
--- > instance Unfoldable Tree where
--- >   unfoldMap f = choose
--- >     [ const Empty
--- >     , Leaf . f
--- >     , spread $ Node <$> to (unfoldMap f) <*> to f <*> to (unfoldMap f)
--- >     ]
-class Unfoldable f where
-  -- | Given a function to generate an element from a seed, 
-  -- and an initial seed, generate a structure.
-  unfoldMap :: Splittable s => (s -> a) -> s -> f a
+-- i.e. it follows closely the instance for 'Traversable', but instead of matching on an input value,
+-- we 'choose' from a list of all cases.
+class Unfoldable t where
+  -- | Given a way to generate elements, return a way to generate structures containing those elements.
+  unfold :: Unfolder f => f a -> f (t a)
 
--- | The same as @unfoldMap id@.
-unfold :: (Unfoldable f, Splittable s) => s -> f s
-unfold = unfoldMap id
+-- | Unfold the structure, always using '()' as elements.
+unfold_ :: (Unfoldable t, Unfolder f) => f (t ())
+unfold_ = unfold (pure ())
 
+-- | Breadth-first unfold
+unfoldBF :: (Unfoldable t, Unfolder f, Alternative f) => f a -> f (t a)
+unfoldBF = runBFS . unfold . packBFS
+
+-- | Unfold the structure breadth-first, always using '()' as elements.
+unfoldBF_ :: (Unfoldable t, Unfolder f, Alternative f) => f (t ())
+unfoldBF_ = unfoldBF (pure ())
+
 -- | Always choose the first constructor.
-leftMost :: Unfoldable f => f ()
-leftMost = unfoldMap (const ()) L
+leftMost :: Unfoldable t => t ()
+leftMost = runIdentity $ getL unfold_
 
 -- | Always choose the last constructor.
-rightMost :: Unfoldable f => f ()
-rightMost = unfoldMap (const ()) R
+rightMost :: Unfoldable t => t ()
+rightMost = runIdentity $ getR unfold_
 
--- | Count the number of times 'to' is used, and split the seed in that many parts.
-spread :: Splittable s => State ([s], Int) a -> s -> a
-spread f s = let (a, (_, i)) = runState f (split i s, 0) in a
+-- | Generate all the values depth first.
+allDepthFirst :: Unfoldable t => [t ()]
+allDepthFirst = unfold_
 
--- | Signal to 'spread' that this is a subpart that needs a seed.
-to :: (s -> a) -> State ([s], Int) a
-to f = state $ \(ss, i) -> (f (head ss), (tail ss, i + 1))
+-- | Generate all the values breadth first.
+allBreadthFirst :: Unfoldable t => [t ()]
+allBreadthFirst = unfoldBF_
 
+-- | Generate a random value, can be used as default instance for Random.
+randomDefault :: (R.Random a, R.RandomGen g, Unfoldable t) => g -> (t a, g)
+randomDefault = runState . getRandom . unfold . Random . state $ R.random
+
+fromList' :: (Unfolder f, MonadPlus f, Unfoldable t) => [a] -> f (t a, [a])
+fromList' as = flip runStateT as . unfoldBF . StateT $ uncons
+  where
+    uncons [] = mzero
+    uncons (a:as') = return (a, as')
+
+-- | Create a data structure using the list as input.
+--   This can fail because there might not be a data structure with the same number
+--   of element positions as the number of elements in the list.
+fromList :: Unfoldable t => [a] -> Maybe (t a)
+fromList as = listToMaybe [ t | (t, []) <- fromList' as ]
+
 instance Unfoldable [] where
-  unfoldMap f = go
-    where
-      go = choose [const [], spread $ (:) <$> to f <*> to go]
+  unfold f = choose 
+    [ pure []
+    , (:) <$> f <*> unfold f
+    ]
 
 instance Unfoldable Maybe where
-  unfoldMap f = choose [const Nothing, Just . f]
+  unfold f = choose 
+    [ pure Nothing
+    , Just <$> f
+    ]
 
 instance (Bounded a, Enum a) => Unfoldable (Either a) where
-  unfoldMap f = choose [Left . boundedEnum, Right . f]
+  unfold f = choose 
+    [ Left <$> boundedEnum
+    , Right <$> f
+    ]
 
 instance (Bounded a, Enum a) => Unfoldable ((,) a) where
-  unfoldMap f = spread $ (,) <$> to boundedEnum <*> to f
+  unfold f = (,) <$> boundedEnum <*> f
 
 instance Unfoldable Identity where
-  unfoldMap f = Identity . f
+  unfold f = Identity <$> f
 
 instance (Bounded a, Enum a) => Unfoldable (Constant a) where
-  unfoldMap _ = Constant . boundedEnum
+  unfold _ = Constant <$> boundedEnum
   
 instance (Unfoldable p, Unfoldable q) => Unfoldable (Product p q) where
-  unfoldMap f = spread $ Pair <$> to (unfoldMap f) <*> to (unfoldMap f)
+  unfold f = Pair <$> unfold f <*> unfold f
 
 instance (Unfoldable p, Unfoldable q) => Unfoldable (Compose p q) where
-  unfoldMap f = Compose . unfoldMap (unfoldMap f)
+  unfold f = Compose <$> unfold (unfold f)
 
 instance Unfoldable f => Unfoldable (Reverse f) where
-  unfoldMap f = Reverse . unfoldMap (f . getDual) . Dual
+  unfold f = Reverse <$> getReverse (unfold (Reverse f))
diff --git a/src/Data/Unfolder.hs b/src/Data/Unfolder.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Unfolder.hs
@@ -0,0 +1,133 @@
+{-# LANGUAGE 
+    ScopedTypeVariables
+  , GeneralizedNewtypeDeriving
+  #-}
+module Data.Unfolder 
+  (
+    Unfolder(..)
+  , chooseDefault
+  
+  , boundedEnum
+  
+  , Left(..)
+  , Right(..)
+  , Random(..)
+
+  , BFS(..)
+  , runBFS
+  , packBFS
+  
+  ) 
+  where 
+
+import Control.Applicative
+import Data.Functor.Identity
+import Data.Functor.Product
+import Data.Functor.Compose
+import Data.Functor.Reverse
+import Control.Monad.Trans.Cont
+import Control.Monad.Trans.Reader
+import Control.Monad.Trans.State
+import qualified System.Random as R
+import Data.Foldable (asum)
+import Data.Maybe (catMaybes)
+
+-- | Unfolders provide a way to unfold data structures. The minimal implementation is 'choose'.
+class Applicative f => Unfolder f where
+  -- | Choose one of the values from the list.
+  choose :: [f x] -> f x
+  -- | Given a number 'n', return a number between '0' and 'n - 1'.
+  chooseInt :: Int -> f Int
+  chooseInt n = choose $ map pure [0 .. n - 1]
+
+-- | If an unfolder is monadic, 'choose' can be implemented in terms of 'chooseInt'.
+chooseDefault :: (Monad m, Unfolder m) => [m x] -> m x
+chooseDefault ms = chooseInt (length ms) >>= (ms !!)
+
+-- | If a datatype is bounded and enumerable, we can use 'chooseInt' to generate a value.
+boundedEnum :: forall f a. (Unfolder f, Bounded a, Enum a) => f a
+boundedEnum = (\x -> toEnum (x + lb)) <$> chooseInt (1 + ub - lb)
+  where
+    lb = fromEnum (minBound :: a)
+    ub = fromEnum (maxBound :: a)
+
+newtype Left x = L { getL :: Identity x } deriving (Functor, Applicative, Monad)
+-- | Always choose the first item.
+instance Unfolder Left where
+  choose = head
+  chooseInt _ = pure 0
+
+newtype Right x = R { getR :: Identity x } deriving (Functor, Applicative, Monad)
+-- | Always choose the last item.
+instance Unfolder Right where
+  choose = last
+  chooseInt n = pure (n - 1)
+
+-- | Don't choose but return all items.
+instance Unfolder [] where
+  choose = concat
+  chooseInt n = [0 .. n - 1]
+
+fstP :: Product p q a -> p a
+fstP (Pair p _) = p
+
+sndP :: Product p q a -> q a
+sndP (Pair _ q) = q
+
+instance (Unfolder p, Unfolder q) => Unfolder (Product p q) where
+  chooseInt n = Pair (chooseInt n) (chooseInt n)
+  choose ps = Pair (choose $ map fstP ps) (choose $ map sndP ps)
+
+instance (Unfolder p, Applicative q) => Unfolder (Compose p q) where
+  chooseInt n = Compose $ pure <$> chooseInt n
+  choose = Compose . choose . map getCompose
+
+instance Unfolder m => Unfolder (Reverse m) where
+  chooseInt n = Reverse $ (\x -> n - 1 - x) <$> chooseInt n
+  choose = Reverse . choose . reverse . map getReverse
+  
+instance (Monad m, Unfolder m) => Unfolder (StateT s m) where
+  choose ms = StateT $ \as -> choose $ map (`runStateT` as) ms
+
+instance Unfolder m => Unfolder (ContT r m) where
+  choose ms = ContT $ \k -> choose $ map (`runContT` k) ms
+
+instance Unfolder m => Unfolder (ReaderT r m) where
+  choose ms = ReaderT $ \r -> choose $ map (`runReaderT` r) ms
+  
+newtype Random g m a = Random { getRandom :: StateT g m a } 
+  deriving (Functor, Applicative, Monad)
+-- | Choose randomly.
+instance (Functor m, Monad m, R.RandomGen g) => Unfolder (Random g m) where
+  choose = chooseDefault
+  chooseInt n = Random . StateT $ return . R.randomR (0, n - 1)
+  
+-- | Return a generator of values of a given depth.
+--   Returns 'Nothing' if there are no values of that depth or deeper.
+newtype BFS f x = BFS { getBFS :: Int -> Maybe (f x) }
+
+instance Functor f => Functor (BFS f) where 
+  fmap f = BFS . (fmap (fmap f) .) . getBFS
+
+instance Alternative f => Applicative (BFS f) where
+  pure = packBFS . pure
+  BFS ff <*> BFS fx = BFS $ \d -> flattenBFS asum $
+    [ (<*>) <$> ff i <*> fx d | i <- [0 .. d - 1] ] ++
+    [ (<*>) <$> ff d <*> fx i | i <- [0 .. d] ]
+
+-- | Choose between values of a given depth only.
+instance (Alternative f, Unfolder f) => Unfolder (BFS f) where
+  choose ms = BFS $ \d -> if d == 0 
+    then Just empty
+    else flattenBFS choose (map (`getBFS` (d - 1)) ms)
+
+runBFS :: Alternative f => BFS f x -> f x
+runBFS (BFS f) = loop 0 where loop d = maybe empty (<|> loop (d + 1)) (f d)
+
+packBFS :: f x -> BFS f x
+packBFS r = BFS $ \d -> if d == 0 then Just r else Nothing
+
+flattenBFS :: ([a] -> a) -> [Maybe a] -> Maybe a
+flattenBFS f ms = case catMaybes ms of
+  [] -> Nothing
+  ms' -> Just (f ms')
diff --git a/unfoldable.cabal b/unfoldable.cabal
--- a/unfoldable.cabal
+++ b/unfoldable.cabal
@@ -1,20 +1,29 @@
-Name:                unfoldable
-Version:             0.2.0
-Synopsis:            Class of data structures that can be unfolded from a seed value.
-Homepage:            https://github.com/sjoerdvisscher/unfoldable
-License:             BSD3
-License-file:        LICENSE
-Author:              Sjoerd Visscher
-Maintainer:          sjoerd@w3future.com
-Category:            Generics
-Build-type:          Simple
-Cabal-version:       >= 1.6
+Name:                 unfoldable
+Version:              0.3.0
+Synopsis:             Class of data structures that can be unfolded.
+Description:          Just as there's a Foldable class, there should also be an Unfoldable class. 
+                      This package provides one. Example unfolds are:
+                      .
+                      * Random values
+                      * Enumeration of all values (depth-first or breadth-first)
+                      * Convert from a list
+                      .
+                      The package provides examples in the examples directory.
+Homepage:             https://github.com/sjoerdvisscher/unfoldable
+Bug-reports:          https://github.com/sjoerdvisscher/data-category/issues
+License:              BSD3
+License-file:         LICENSE
+Author:               Sjoerd Visscher
+Maintainer:           sjoerd@w3future.com
+Category:             Generics
+Build-type:           Simple
+Cabal-version:        >= 1.6
 
 Library
   HS-Source-Dirs:  src
   
   Exposed-modules:
-    Data.Splittable
+    Data.Unfolder
     Data.Unfoldable  
   
   Build-depends:
