diff --git a/Control/Comonad/Random.hs b/Control/Comonad/Random.hs
new file mode 100644
--- /dev/null
+++ b/Control/Comonad/Random.hs
@@ -0,0 +1,131 @@
+{-# LANGUAGE GeneralizedNewtypeDeriving, Rank2Types #-}
+
+-- | This module provides a comonadic interface to random values. In
+--   some situations, this may be more natural than a monadic
+--   approach.
+module Control.Comonad.Random
+    ( module Control.Comonad
+    , module System.Random
+
+      -- * Example
+      -- $Example
+
+      -- * Data Type
+    , Rand ()
+
+      -- ** Creation
+    , mkRand
+    , mkRandR
+
+      -- ** Transformations
+    , next
+    , left
+    , right
+
+      -- ** Convenience
+    , extracts
+    )
+    where
+
+import Control.Applicative
+import Control.Comonad
+import Control.Comonad.Cofree
+import Control.Functor.Pointed
+import Data.Function
+import System.Random hiding (next)
+
+newtype Three a = Three (a, a, a)
+
+fst3 :: Three a -> a
+fst3 (Three (x, _, _)) = x
+
+snd3 :: Three a -> a
+snd3 (Three (_, y, _)) = y
+
+thd3 :: Three a -> a
+thd3 (Three (_, _, z)) = z
+
+instance Functor Three where
+    fmap f (Three ~(x, y, z)) = Three (f x, f y, f z)
+
+instance Applicative Three where
+    pure x = Three (x, x, x)
+    Three ~(f, g, h) <*> Three ~(x, y, z) = Three (f x, g y, h z)
+
+-- | A memoized supply of values
+newtype Rand a = Rand { unRand :: Cofree Three a }
+    deriving (Functor, Copointed, Comonad)
+
+inRand :: (Cofree Three a -> Cofree Three b) -> (Rand a -> Rand b)
+inRand = (Rand .) . (. unRand)
+
+instance Applicative Rand where
+    pure x = let tree = cofree x $ Three (tree, tree, tree)
+             in Rand tree
+    Rand a <*> Rand b = let ~(f, fs) = runCofree a
+                            ~(x, xs) = runCofree b
+                        in Rand . cofree (f x) . fmap unRand .
+                           liftA2 (<*>) (fmap Rand fs) . fmap Rand $ xs
+
+mkRandWith :: RandomGen g => (g -> (a, g)) -> g -> Rand a
+mkRandWith f g = let ~(x, g') = f g
+                     ~(l, r) = split g
+                 in Rand . cofree x . fmap (unRand . mkRandWith f) . Three $ (l, g', r)
+
+
+-- | Create a comonadic generator from a 'RandomGen'.
+mkRand :: (RandomGen g, Random a) => g -> Rand a
+mkRand = mkRandWith random
+
+-- | Create a comonadic generator from a 'RandomGen' where the values
+--   are limited to a given range.
+mkRandR :: (RandomGen g, Random a) => (a, a) -> g -> Rand a
+mkRandR = mkRandWith . randomR
+
+inner :: (forall b . Three b -> b) -> (Rand a -> Rand a)
+inner f = inRand $ f . snd . runCofree
+
+-- | Get the generator for the next value.
+next :: Rand a -> Rand a
+next = inner snd3
+
+-- | Split the generator, returning the new left one.
+left :: Rand a -> Rand a
+left = inner fst3
+
+-- | Split the generator, returning the new right one.
+right :: Rand a -> Rand a
+right = inner thd3
+
+-- | Generate an infinite list of values by applying a function
+--   repeatedly.
+extracts :: (Rand a -> Rand a) -> Rand a -> [a]
+extracts f = liftA2 (:) extract (extracts f . f)
+
+{- $Example
+
+   This example is based on the example given in the MonadRandom
+   package.
+
+   @rolls@ is a supply of random dice rolls, picking a number between
+   1 and 6, inclusive.
+
+> rolls :: RandomGen g => g -> Rand Int
+> rolls = mkRandR (1, 6)
+
+   @extractN@ may be used to supply @n@ values from a @Rand@.
+
+> extractN :: Int -> Rand a -> [a]
+> extractN n = take n . extracts next
+
+   We can bootstrap the whole thing with a generator, giving us a pure
+   interface to the random values.
+
+> main = print . extractN 2 . rolls =<< getStdGen
+
+   One potential gotcha with this library is that a top-level @Rand@
+   that is extracted deeply could result in a space leak due to the
+   memoization. It's a good idea to try not to hold on to @Rand@s for
+   longer than necessary.
+
+-}
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,15 @@
+Copyright © 2009, Jake McArthur
+
+Permission to use, copy, modify, and/or distribute this software for
+any purpose with or without fee is hereby granted, provided that the
+above copyright notice and this permission notice appear in all
+copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/comonad-random.cabal b/comonad-random.cabal
new file mode 100644
--- /dev/null
+++ b/comonad-random.cabal
@@ -0,0 +1,14 @@
+name:                comonad-random
+version:             0.1.0
+synopsis:            Comonadic interface for random values
+description:         Comonadic interface for random values
+category:            Control
+license:             OtherLicense
+license-file:        LICENSE
+author:              Jake McArthur
+maintainer:          Jake.McArthur@gmail.com
+build-depends:       base >= 4 && < 5, category-extras >= 0.53.5 && < 0.54,
+                     random >= 1.0.0.1 && < 1.1
+build-type:          Simple
+ghc-options:         -Wall
+exposed-modules:     Control.Comonad.Random
