https://github.com/evolution-gaming/random
Pure random number generator
https://github.com/evolution-gaming/random
cats random rng scala
Last synced: 14 days ago
JSON representation
Pure random number generator
- Host: GitHub
- URL: https://github.com/evolution-gaming/random
- Owner: evolution-gaming
- License: mit
- Created: 2019-03-06T20:27:51.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2025-08-27T10:02:35.000Z (2 months ago)
- Last Synced: 2025-10-14T19:37:45.799Z (14 days ago)
- Topics: cats, random, rng, scala
- Language: Scala
- Size: 161 KB
- Stars: 4
- Watchers: 10
- Forks: 3
- Open Issues: 9
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Random
[](https://github.com/evolution-gaming/random/actions?query=workflow%3ACI)
[](https://coveralls.io/r/evolution-gaming/random)
[](https://app.codacy.com/gh/evolution-gaming/random/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
[](https://evolution.jfrog.io/ui/packages/gav:%2F%2Fcom.evolution:random_2.13)
[](https://opensource.org/licenses/MIT)
Pure deterministic pseudo-random number generator, which returns a new state on each call.
The returned state could be used to generate a next random value, without
relying for it to be saved in a mutable variable inside of the RNG library.
It could be useful for writing the code, when the direct usage of an effect
system such as `cats.effect.IO` is either not possible or not desired. Also,
the versions `0.1.1` and below are compatible with Cats Effect 2.
If the application already uses Cats Effect 3 and pure random generator is not
required then https://typelevel.org/cats-effect/docs/std/random might be a
preferred choice for sake of using a more standard solution.
```scala
trait Random[F[_]] {
def int: F[Int]
def long: F[Long]
def float: F[Float]
def double: F[Double]
}
```
## Setup
```scala
addSbtPlugin("com.evolution" % "sbt-artifactory-plugin" % "0.0.2")
libraryDependencies += "com.evolution" %% "random" % "1.0.5"
```
## Usage
The library could be used directly with pure Scala without any additional effect systems:
```scala
def currentTimeSeedExample(): Unit = {
// note, that current time could be a bad choice for a seed
val state0 = Random.State(System.currentTimeMillis())
val (state1, n0) = state0.int
val (_, n1) = state1.int
println(s"Two random numbers: $n0, $n1")
}
```
It also includes facilities to create a random number generator with a safe seed based on the current time from Cats Effect `Clock` instance:
```scala
def clockSeedExample: IO[Unit] =
for {
state0 <- Random.State.fromClock[IO]()
(state1, n0) = state0.int
(_, n1) = state1.int
_ <- IO.println(s"Two random numbers: $n0, $n1")
} yield ()
```
The typical Cats Effect user might prefer storing these instances in `IOLocal`
for efficiency and code readability (i.e. to not pass a state manually around):
``` scala
def ioLocalExample: IO[Unit] =
for {
random <- IOLocalRandom.fromClock
n0 <- random.int
n1 <- random.int
_ <- IO.println(s"Two random numbers: $n0, $n1")
} yield ()
object IOLocalRandom {
def fromClock: IO[Random[IO]] =
for {
random <- Random.State.fromClock[IO]()
random <- IOLocal(random)
} yield new Random[IO] {
def int: IO[Int] = random.modify(_.int)
def long: IO[Long] = random.modify(_.long)
def float: IO[Float] = random.modify(_.float)
def double: IO[Double] = random.modify(_.double)
}
}
```
It is also possible to use the same approach in a Tagless Final environment
using `ThreadLocalOf` from Cats Helper library:
```scala
import com.evolutiongaming.catshelper.ThreadLocalOf
def threadLocalExample[F[_]: Monad: Clock: Console: ThreadLocalOf]: F[Unit] =
for {
random <- ThreadLocalRandom.fromClock[F]
n0 <- random.int
n1 <- random.int
_ <- Console[F].println(s"Two random numbers: $n0, $n1")
} yield ()
object ThreadLocalRandom {
def fromClock[F[_]: Monad: Clock: ThreadLocalOf]: F[Random[F]] =
for {
random <- Random.State.fromClock[F]()
random <- ThreadLocalOf[F].apply(random)
} yield new Random[F] {
def int: F[Int] = random.modify(_.int)
def long: F[Long] = random.modify(_.long)
def float: F[Float] = random.modify(_.float)
def double: F[Double] = random.modify(_.double)
}
}
```