Skip to content

Commit

Permalink
Add materializers for monad transformers
Browse files Browse the repository at this point in the history
  • Loading branch information
alexandrustana committed Mar 29, 2021
1 parent 5b08590 commit 7bc36e9
Showing 1 changed file with 123 additions and 1 deletion.
124 changes: 123 additions & 1 deletion std/shared/src/main/scala/cats/effect/std/Random.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package std

import cats._
import cats.syntax.all._
import cats.data.{EitherT, IorT, Kleisli, OptionT, ReaderWriterStateT, StateT, WriterT}
import cats.effect.kernel._
import scala.util.{Random => SRandom}

Expand All @@ -29,7 +30,7 @@ import scala.util.{Random => SRandom}
*
* Alumnus of the Davenverse.
*/
trait Random[F[_]] {
trait Random[F[_]] { self =>

/**
* Returns the next pseudorandom, uniformly distributed double value between min (inclusive) and max (exclusive) from this random number generator's sequence.
Expand Down Expand Up @@ -125,6 +126,70 @@ trait Random[F[_]] {
*/
def shuffleVector[A](v: Vector[A]): F[Vector[A]]

/**
* Modifies the context in which this [[Random]] operates using the natural
* transformation `f`.
*
* @return a [[Random]] in the new context obtained by mapping the current one
* using `f`
*/
def mapK[G[_]](f: F ~> G): Random[G] =
new Random[G] {
override def betweenDouble(minInclusive: Double, maxExclusive: Double): G[Double] =
f(self.betweenDouble(minInclusive, maxExclusive))

override def betweenFloat(minInclusive: Float, maxExclusive: Float): G[Float] =
f(self.betweenFloat(minInclusive, maxExclusive))

override def betweenInt(minInclusive: Int, maxExclusive: Int): G[Int] =
f(self.betweenInt(minInclusive, maxExclusive))

override def betweenLong(minInclusive: Long, maxExclusive: Long): G[Long] =
f(self.betweenLong(minInclusive, maxExclusive))

override def nextAlphaNumeric: G[Char] =
f(self.nextAlphaNumeric)

override def nextBoolean: G[Boolean] =
f(self.nextBoolean)

override def nextBytes(n: Int): G[Array[Byte]] =
f(self.nextBytes(n))

override def nextDouble: G[Double] =
f(self.nextDouble)

override def nextFloat: G[Float] =
f(self.nextFloat)

override def nextGaussian: G[Double] =
f(self.nextGaussian)

override def nextInt: G[Int] =
f(self.nextInt)

override def nextIntBounded(n: Int): G[Int] =
f(self.nextIntBounded(n))

override def nextLong: G[Long] =
f(self.nextLong)

override def nextLongBounded(n: Long): G[Long] =
f(self.nextLongBounded(n))

override def nextPrintableChar: G[Char] =
f(self.nextPrintableChar)

override def nextString(length: Int): G[String] =
f(self.nextString(length))

override def shuffleList[A](l: List[A]): G[List[A]] =
f(self.shuffleList(l))

override def shuffleVector[A](v: Vector[A]): G[Vector[A]] =
f(self.shuffleVector(v))

}
}

object Random {
Expand All @@ -140,6 +205,63 @@ object Random {
new ScalaRandom[F](sRandom.pure[F]) {}
}

/**
* [[Random]] instance built for `cats.data.EitherT` values initialized with
* any `F` data type that also implements `Random`.
*/
implicit def catsEitherTRandom[F[_]: Random: Functor, L]: Random[EitherT[F, L, *]] =
Random[F].mapK(EitherT.liftK)

/**
* [[Random]] instance built for `cats.data.Kleisli` values initialized with
* any `F` data type that also implements `Random`.
*/
implicit def catsKleisliRandom[F[_]: Random, R]: Random[Kleisli[F, R, *]] =
Random[F].mapK(Kleisli.liftK)

/**
* [[Random]] instance built for `cats.data.OptionT` values initialized with
* any `F` data type that also implements `Random`.
*/
implicit def catsOptionTRandom[F[_]: Random: Functor]: Random[OptionT[F, *]] =
Random[F].mapK(OptionT.liftK)

/**
* [[Random]] instance built for `cats.data.StateT` values initialized with
* any `F` data type that also implements `Random`.
*/
implicit def catsStateTRandom[F[_]: Random: Applicative, S]: Random[StateT[F, S, *]] =
Random[F].mapK(StateT.liftK)

/**
* [[Random]] instance built for `cats.data.WriterT` values initialized with
* any `F` data type that also implements `Random`.
*/
implicit def catsWriterTRandom[
F[_]: Random: Applicative,
L: Monoid
]: Random[WriterT[F, L, *]] =
Random[F].mapK(WriterT.liftK)

/**
* [[Random]] instance built for `cats.data.IorT` values initialized with any
* `F` data type that also implements `Random`.
*/
implicit def catsIorTRandom[F[_]: Random: Functor, L]: Random[IorT[F, L, *]] =
Random[F].mapK(IorT.liftK)

/**
* [[Random]] instance built for `cats.data.ReaderWriterStateT` values
* initialized with any `F` data type that also implements `Random`.
*/
implicit def catsReaderWriterStateTRandom[
F[_]: Random: Applicative,
E,
L: Monoid,
S
]: Random[ReaderWriterStateT[F, E, L, S, *]] =
Random[F].mapK(ReaderWriterStateT.liftK)

/**
* Creates Several Random Number Generators and equally
* allocates the load across those instances.
Expand Down

0 comments on commit 7bc36e9

Please sign in to comment.