fused-effects-random 1.0.0.0 → 1.1.0.0
raw patch · 6 files changed
+182/−119 lines, 6 filesdep −MonadRandomdep ~basedep ~fused-effectsdep ~randomnew-uploaderPVP ok
version bump matches the API change (PVP)
Dependencies removed: MonadRandom
Dependency ranges changed: base, fused-effects, random
API changes (from Hackage documentation)
- Control.Effect.Random: Interleave :: m a -> (a -> m k) -> Random m k
- Control.Effect.Random: Random :: (a -> m k) -> Random m k
- Control.Effect.Random: RandomC :: StateC g m a -> RandomC g m a
- Control.Effect.Random: RandomR :: (a, a) -> (a -> m k) -> Random m k
- Control.Effect.Random: [runRandomC] :: RandomC g m a -> StateC g m a
- Control.Effect.Random: evalRandom :: Functor m => g -> RandomC g m a -> m a
- Control.Effect.Random: evalRandomIO :: MonadIO m => RandomC StdGen m a -> m a
- Control.Effect.Random: execRandom :: Functor m => g -> RandomC g m a -> m g
- Control.Effect.Random: getRandom :: (Has Random sig m, Random a) => m a
- Control.Effect.Random: getRandomR :: (Has Random sig m, Random a) => (a, a) -> m a
- Control.Effect.Random: instance (Control.Algebra.Algebra sig m, Control.Effect.Class.Effect sig, System.Random.RandomGen g) => Control.Algebra.Algebra (Control.Effect.Random.Random Control.Effect.Sum.:+: sig) (Control.Effect.Random.RandomC g m)
- Control.Effect.Random: instance (Control.Algebra.Algebra sig m, Control.Effect.Class.Effect sig, System.Random.RandomGen g) => Control.Monad.Random.Class.MonadInterleave (Control.Effect.Random.RandomC g m)
- Control.Effect.Random: instance (Control.Algebra.Algebra sig m, Control.Effect.Class.Effect sig, System.Random.RandomGen g) => Control.Monad.Random.Class.MonadRandom (Control.Effect.Random.RandomC g m)
- Control.Effect.Random: instance (GHC.Base.Alternative m, GHC.Base.Monad m) => GHC.Base.Alternative (Control.Effect.Random.RandomC g m)
- Control.Effect.Random: instance (GHC.Base.Alternative m, GHC.Base.Monad m) => GHC.Base.MonadPlus (Control.Effect.Random.RandomC g m)
- Control.Effect.Random: instance Control.Effect.Class.Effect Control.Effect.Random.Random
- Control.Effect.Random: instance Control.Effect.Class.HFunctor Control.Effect.Random.Random
- Control.Effect.Random: instance Control.Monad.Fail.MonadFail m => Control.Monad.Fail.MonadFail (Control.Effect.Random.RandomC g m)
- Control.Effect.Random: instance Control.Monad.Fix.MonadFix m => Control.Monad.Fix.MonadFix (Control.Effect.Random.RandomC g m)
- Control.Effect.Random: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Control.Effect.Random.RandomC g m)
- Control.Effect.Random: instance Control.Monad.Trans.Class.MonadTrans (Control.Effect.Random.RandomC g)
- Control.Effect.Random: instance GHC.Base.Functor m => GHC.Base.Functor (Control.Effect.Random.Random m)
- Control.Effect.Random: instance GHC.Base.Functor m => GHC.Base.Functor (Control.Effect.Random.RandomC g m)
- Control.Effect.Random: instance GHC.Base.Monad m => GHC.Base.Applicative (Control.Effect.Random.RandomC g m)
- Control.Effect.Random: instance GHC.Base.Monad m => GHC.Base.Monad (Control.Effect.Random.RandomC g m)
- Control.Effect.Random: newtype RandomC g m a
- Control.Effect.Random: runRandom :: g -> RandomC g m a -> m (g, a)
+ Control.Carrier.Random.Gen: RandomC :: StateC g m a -> RandomC g m a
+ Control.Carrier.Random.Gen: evalRandom :: Applicative m => g -> RandomC g m a -> m a
+ Control.Carrier.Random.Gen: evalRandomSystem :: MonadIO m => RandomC StdGen m a -> m a
+ Control.Carrier.Random.Gen: execRandom :: Applicative m => g -> RandomC g m a -> m g
+ Control.Carrier.Random.Gen: instance (Control.Algebra.Algebra sig m, System.Random.Internal.RandomGen g) => Control.Algebra.Algebra (Control.Effect.Random.Random Control.Effect.Sum.:+: sig) (Control.Carrier.Random.Gen.RandomC g m)
+ Control.Carrier.Random.Gen: instance (GHC.Base.Alternative m, GHC.Base.Monad m) => GHC.Base.MonadPlus (Control.Carrier.Random.Gen.RandomC g m)
+ Control.Carrier.Random.Gen: instance Control.Monad.Fail.MonadFail m => Control.Monad.Fail.MonadFail (Control.Carrier.Random.Gen.RandomC g m)
+ Control.Carrier.Random.Gen: instance Control.Monad.Fix.MonadFix m => Control.Monad.Fix.MonadFix (Control.Carrier.Random.Gen.RandomC g m)
+ Control.Carrier.Random.Gen: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Control.Carrier.Random.Gen.RandomC g m)
+ Control.Carrier.Random.Gen: instance Control.Monad.Trans.Class.MonadTrans (Control.Carrier.Random.Gen.RandomC g)
+ Control.Carrier.Random.Gen: instance GHC.Base.Alternative m => GHC.Base.Alternative (Control.Carrier.Random.Gen.RandomC g m)
+ Control.Carrier.Random.Gen: instance GHC.Base.Applicative (Control.Carrier.Random.Gen.RandomC g m)
+ Control.Carrier.Random.Gen: instance GHC.Base.Functor (Control.Carrier.Random.Gen.RandomC g m)
+ Control.Carrier.Random.Gen: instance GHC.Base.Monad (Control.Carrier.Random.Gen.RandomC g m)
+ Control.Carrier.Random.Gen: newtype RandomC g m a
+ Control.Carrier.Random.Gen: runRandom :: Applicative m => g -> RandomC g m a -> m (g, a)
+ Control.Effect.Random: [Interleave] :: m a -> Random m a
+ Control.Effect.Random: [UniformR] :: Random a => (a, a) -> Random m a
+ Control.Effect.Random: [Uniform] :: Random a => Random m a
+ Control.Effect.Random: class Monad m => Algebra (sig :: Type -> Type -> Type -> Type) (m :: Type -> Type) | m -> sig
+ Control.Effect.Random: exponential :: (Random a, Floating a, Has Random sig m) => a -> m a
+ Control.Effect.Random: uniform :: (Random a, Has Random sig m) => m a
+ Control.Effect.Random: uniformR :: (Random a, Has Random sig m) => (a, a) -> m a
- Control.Effect.Random: run :: () => Identity a -> a
+ Control.Effect.Random: run :: Identity a -> a
Files
- CHANGELOG.md +19/−0
- LICENSE +1/−1
- README.md +6/−0
- fused-effects-random.cabal +17/−13
- src/Control/Carrier/Random/Gen.hs +85/−0
- src/Control/Effect/Random.hs +54/−105
CHANGELOG.md view
@@ -1,6 +1,25 @@+# 1.1++- Support for `random` 1.2.++- Support for `ghc` 8.10.+++## Backwards-incompatible changes++- Support for `fused-effects` 1.1.++- Moves the `RandomC` carrier into its own module, `Control.Carrier.Random.Gen`.++- Renames the `Random` effect’s operations.++- Adds an operation producing an exponential distribution.++ # 1.0.0.0 - Port to `fused-effects` 1.+ # 0.0.0.0
LICENSE view
@@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2018-2019, Nicolas Wu, Tom Schrijvers, Rob Rix, and Patrick Thomson+Copyright (c) 2019-2020, Rob Rix All rights reserved. Redistribution and use in source and binary forms, with or without
+ README.md view
@@ -0,0 +1,6 @@+# fused-effects-random++[](LICENSE)+[](https://github.com/fused-effects/fused-effects-exceptions/actions)++This package provides a random number generation effect for [`fused-effects`](https://github.com/fused-effects/fused-effects) that wraps the API provided by `System.Random`.
fused-effects-random.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.2 name: fused-effects-random-version: 1.0.0.0+version: 1.1.0.0 synopsis: Random number generation for fused-effects. description: Random number generation as an effect using fused-effects. homepage: https://github.com/fused-effects/fused-effects-random@@ -10,14 +10,15 @@ license-file: LICENSE author: Rob Rix maintainer: robrix@github.com-copyright: 2019 Rob Rix+copyright: 2019-2020 Rob Rix category: Control build-type: Simple extra-source-files: CHANGELOG.md+ README.md common common- default-language: Haskell2010+ default-language: Haskell2010 ghc-options: -Weverything -Wno-all-missed-specialisations@@ -29,21 +30,24 @@ -Wno-name-shadowing -Wno-safe -Wno-unsafe- if (impl(ghc >= 8.6))+ if (impl(ghc >= 8.8))+ ghc-options: -Wno-missing-deriving-strategies+ if (impl(ghc >= 8.10)) ghc-options:- -Wno-star-is-type+ -Wno-missing-safe-haskell-mode+ -Wno-prepositive-qualified-module library- import: common+ import: common exposed-modules:+ Control.Carrier.Random.Gen Control.Effect.Random- build-depends: base >=4.10 && <4.15- , fused-effects ^>= 1- , MonadRandom ^>= 0.5.1.1- , random ^>= 1.1- , transformers >= 0.4 && <0.6- hs-source-dirs: src- default-language: Haskell2010+ build-depends:+ , base >=4.10 && < 5+ , fused-effects ^>= 1.1+ , random >= 1.1 && < 1.3+ , transformers >= 0.4 && <0.6+ hs-source-dirs: src source-repository head type: git
+ src/Control/Carrier/Random/Gen.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+-- | A carrier for "Control.Effect.Random".'Random' implemented using 'R.RandomGen'.+--+-- @since 1.1+module Control.Carrier.Random.Gen+( -- * Random carrier+ runRandom+, evalRandom+, execRandom+, evalRandomSystem+, RandomC(RandomC)+ -- * Random effect+, module Control.Effect.Random+) where++import Control.Algebra+import Control.Applicative (Alternative)+import Control.Carrier.State.Church+import Control.Effect.Random+import Control.Monad (MonadPlus)+import qualified Control.Monad.Fail as Fail+import Control.Monad.Fix+import Control.Monad.IO.Class (MonadIO(..))+import Control.Monad.Trans.Class+import qualified System.Random as R (Random(..), RandomGen(..), StdGen, newStdGen)++-- | Run a random computation starting from a given generator.+--+-- @+-- 'runRandom' g ('pure' b) = 'pure' (g, b)+-- @+--+-- @since 1.0+runRandom :: Applicative m => g -> RandomC g m a -> m (g, a)+runRandom g = runState (curry pure) g . runRandomC+{-# INLINE runRandom #-}++-- | Run a random computation starting from a given generator and discarding the final generator.+--+-- @+-- 'evalRandom' g ('pure' b) = 'pure' b+-- @+--+-- @since 1.0+evalRandom :: Applicative m => g -> RandomC g m a -> m a+evalRandom g = evalState g . runRandomC+{-# INLINE evalRandom #-}++-- | Run a random computation starting from a given generator and discarding the final result.+--+-- @+-- 'execRandom' g ('pure' b) = g+-- @+--+-- @since 1.0+execRandom :: Applicative m => g -> RandomC g m a -> m g+execRandom g = execState g . runRandomC+{-# INLINE execRandom #-}++-- | Run a random computation in 'IO', splitting the global standard generator to get a new one for the computation.+--+-- @since 1.1+evalRandomSystem :: MonadIO m => RandomC R.StdGen m a -> m a+evalRandomSystem m = liftIO R.newStdGen >>= flip evalRandom m+{-# INLINE evalRandomSystem #-}++-- | A carrier for 'Random' implemented using 'R.RandomGen'.+--+-- @since 1.0+newtype RandomC g m a = RandomC { runRandomC :: StateC g m a }+ deriving (Alternative, Applicative, Functor, Monad, Fail.MonadFail, MonadFix, MonadIO, MonadPlus, MonadTrans)++instance (Algebra sig m, R.RandomGen g) => Algebra (Random :+: sig) (RandomC g m) where+ alg hdl sig ctx = RandomC $ case sig of+ L random -> StateC $ \ k g -> case random of+ Uniform -> let (a, g') = R.random g in k g' (a <$ ctx)+ UniformR r -> let (a, g') = R.randomR r g in k g' (a <$ ctx)+ Interleave m -> let (g'', g') = R.split g in runState (const (k g'')) g' (runRandomC (hdl (m <$ ctx)))+ R other -> alg (runRandomC . hdl) (R other) ctx+ {-# INLINE alg #-}
src/Control/Effect/Random.hs view
@@ -1,125 +1,74 @@-{-# LANGUAGE DeriveFunctor, ExistentialQuantification, FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, ScopedTypeVariables, StandaloneDeriving, TypeOperators, UndecidableInstances #-}+{-# LANGUAGE GADTs #-}+-- | Random variables in uniform and exponential distributions, with interleaving.+--+-- @since 1.0 module Control.Effect.Random ( -- * Random effect Random(..)-, getRandom-, getRandomR+, uniform+, uniformR , interleave- -- * Random carrier-, runRandom-, evalRandom-, execRandom-, evalRandomIO-, RandomC(..)+ -- * Non-uniform distributions+, exponential -- * Re-exports+, Algebra , Has , run ) where -import Control.Algebra-import Control.Applicative (Alternative(..))-import Control.Carrier.State.Strict-import Control.Monad (MonadPlus(..))-import Control.Monad.Fail-import Control.Monad.Fix-import qualified Control.Monad.Random.Class as R-import Control.Monad.IO.Class (MonadIO(..))-import Control.Monad.Trans.Class-import qualified System.Random as R (Random(..), RandomGen(..), StdGen, newStdGen)--data Random m k- = forall a . R.Random a => Random (a -> m k)- | forall a . R.Random a => RandomR (a, a) (a -> m k)- | forall a . Interleave (m a) (a -> m k)--deriving instance Functor m => Functor (Random m)--instance HFunctor Random where- hmap f (Random k) = Random (f . k)- hmap f (RandomR r k) = RandomR r (f . k)- hmap f (Interleave m k) = Interleave (f m) (f . k)- {-# INLINE hmap #-}--instance Effect Random where- thread state handler (Random k) = Random (handler . (<$ state) . k)- thread state handler (RandomR r k) = RandomR r (handler . (<$ state) . k)- thread state handler (Interleave m k) = Interleave (handler (m <$ state)) (handler . fmap k)- {-# INLINE thread #-}---getRandom :: (Has Random sig m, R.Random a) => m a-getRandom = send (Random pure)--getRandomR :: (Has Random sig m, R.Random a) => (a, a) -> m a-getRandomR interval = send (RandomR interval pure)+import Control.Algebra+import qualified System.Random as R (Random(..)) -interleave :: (Has Random sig m) => m a -> m a-interleave m = send (Interleave m pure)+-- | Uniformly-distributed random variables, with interleaving.+--+-- @since 1.0+data Random m k where+ Uniform :: R.Random a => Random m a+ UniformR :: R.Random a => (a, a) -> Random m a+ Interleave :: m a -> Random m a --- | Run a random computation starting from a given generator.+-- | Produce a random variable uniformly distributed in a range determined by its type’s 'R.Random' instance. For example: ----- prop> run (runRandom (PureGen a) (pure b)) === (PureGen a, b)-runRandom :: g -> RandomC g m a -> m (g, a)-runRandom g = runState g . runRandomC+-- * bounded types (instances of 'Bounded', such as 'Char') typically sample all of the constructors.+-- * fractional types, the range is normally the semi-closed interval [0,1).+-- * for 'Integer', the range is (arbitrarily) the range of 'Int'.+--+-- @since 1.1+uniform :: (R.Random a, Has Random sig m) => m a+uniform = send Uniform+{-# INLINE uniform #-} --- | Run a random computation starting from a given generator and discarding the final generator.+-- | Produce a random variable uniformly distributed in the given range. ----- prop> run (evalRandom (PureGen a) (pure b)) === b-evalRandom :: Functor m => g -> RandomC g m a -> m a-evalRandom g = fmap snd . runRandom g+-- @+-- 'Data.Ix.inRange' (a, b) '<$>' 'uniformR' (a, b) = 'pure' 'True'+-- @+--+-- @since 1.1+uniformR :: (R.Random a, Has Random sig m) => (a, a) -> m a+uniformR interval = send (UniformR interval)+{-# INLINE uniformR #-} --- | Run a random computation starting from a given generator and discarding the final result.+-- | Run a computation by splitting the generator, using one half for the passed computation and the other for the continuation. ----- prop> run (execRandom (PureGen a) (pure b)) === PureGen a-execRandom :: Functor m => g -> RandomC g m a -> m g-execRandom g = fmap fst . runRandom g+-- @+-- 'interleave' ('pure' a) = 'pure' a+-- @+--+-- @since 1.0+interleave :: Has Random sig m => m a -> m a+interleave m = send (Interleave m)+{-# INLINE interleave #-} --- | Run a random computation in 'IO', splitting the global standard generator to get a new one for the computation.-evalRandomIO :: MonadIO m => RandomC R.StdGen m a -> m a-evalRandomIO m = liftIO R.newStdGen >>= flip evalRandom m -newtype RandomC g m a = RandomC { runRandomC :: StateC g m a }- deriving (Alternative, Applicative, Functor, Monad, MonadFail, MonadFix, MonadIO, MonadPlus, MonadTrans)--instance (Algebra sig m, Effect sig, R.RandomGen g) => R.MonadRandom (RandomC g m) where- getRandom = getRandom- {-# INLINE getRandom #-}- getRandomR = getRandomR- {-# INLINE getRandomR #-}- getRandomRs interval = (:) <$> R.getRandomR interval <*> R.getRandomRs interval- {-# INLINE getRandomRs #-}- getRandoms = (:) <$> R.getRandom <*> R.getRandoms- {-# INLINE getRandoms #-}--instance (Algebra sig m, Effect sig, R.RandomGen g) => R.MonadInterleave (RandomC g m) where- interleave = interleave- {-# INLINE interleave #-}--instance (Algebra sig m, Effect sig, R.RandomGen g) => Algebra (Random :+: sig) (RandomC g m) where- alg (L (Random k)) = RandomC $ do- (a, g') <- gets R.random- put (g' :: g)- runRandomC (k a)- alg (L (RandomR r k)) = RandomC $ do- (a, g') <- gets (R.randomR r)- put (g' :: g)- runRandomC (k a)- alg (L (Interleave m k)) = RandomC $ do- (g1, g2) <- gets R.split- put (g1 :: g)- a <- runRandomC m- put g2- runRandomC (k a)- alg (R other) = RandomC (alg (R (handleCoercible other)))- {-# INLINE alg #-}-+-- * Non-uniform distributions --- $setup--- >>> :seti -XFlexibleContexts--- >>> import System.Random--- >>> import Test.QuickCheck--- >>> import Control.Effect.Pure--- >>> import Control.Effect.NonDet--- >>> newtype PureGen = PureGen Int deriving (Eq, Show)--- >>> instance RandomGen PureGen where next (PureGen i) = (i, PureGen i) ; split g = (g, g)+-- | Produce a random variable in an expnoential distribution with the given scale.+--+-- @since 1.1+exponential :: (R.Random a, Floating a, Has Random sig m) => a -> m a+exponential a = do+ x <- uniform+ pure $! -log x / a+{-# INLINE exponential #-}