packages feed

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 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