comonad-random (empty) → 0.1.0
raw patch · 4 files changed
+163/−0 lines, 4 filesdep +basedep +category-extrasdep +randomsetup-changed
Dependencies added: base, category-extras, random
Files
- Control/Comonad/Random.hs +131/−0
- LICENSE +15/−0
- Setup.lhs +3/−0
- comonad-random.cabal +14/−0
+ Control/Comonad/Random.hs view
@@ -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.++-}
+ LICENSE view
@@ -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.
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ comonad-random.cabal view
@@ -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