From 5ac06d68446789e95b0f39307ec6ec5f2fe6e831 Mon Sep 17 00:00:00 2001 From: alexandrustana Date: Mon, 29 Mar 2021 20:36:57 +0300 Subject: [PATCH 1/2] Add materializers for monad transformers --- .../main/scala/cats/effect/std/Random.scala | 124 +++++++++++++++++- 1 file changed, 123 insertions(+), 1 deletion(-) diff --git a/std/shared/src/main/scala/cats/effect/std/Random.scala b/std/shared/src/main/scala/cats/effect/std/Random.scala index 2d82d79834..d5ccffa4c2 100644 --- a/std/shared/src/main/scala/cats/effect/std/Random.scala +++ b/std/shared/src/main/scala/cats/effect/std/Random.scala @@ -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} @@ -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. @@ -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 { @@ -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. From 5f66fe71c36e3a255b791f0fb59b1ef9a3e60179 Mon Sep 17 00:00:00 2001 From: alexandrustana Date: Mon, 12 Apr 2021 09:50:03 +0300 Subject: [PATCH 2/2] Switch to Indexed --- .../main/scala/cats/effect/std/Random.scala | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/std/shared/src/main/scala/cats/effect/std/Random.scala b/std/shared/src/main/scala/cats/effect/std/Random.scala index d5ccffa4c2..a5a7380bc8 100644 --- a/std/shared/src/main/scala/cats/effect/std/Random.scala +++ b/std/shared/src/main/scala/cats/effect/std/Random.scala @@ -20,7 +20,15 @@ package std import cats._ import cats.syntax.all._ -import cats.data.{EitherT, IorT, Kleisli, OptionT, ReaderWriterStateT, StateT, WriterT} +import cats.data.{ + EitherT, + IndexedReaderWriterStateT, + IndexedStateT, + IorT, + Kleisli, + OptionT, + WriterT +} import cats.effect.kernel._ import scala.util.{Random => SRandom} @@ -227,11 +235,12 @@ object Random { Random[F].mapK(OptionT.liftK) /** - * [[Random]] instance built for `cats.data.StateT` values initialized with + * [[Random]] instance built for `cats.data.IndexedStateT` 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) + implicit def catsIndexedStateTRandom[F[_]: Random: Applicative, S] + : Random[IndexedStateT[F, S, S, *]] = + Random[F].mapK(IndexedStateT.liftK) /** * [[Random]] instance built for `cats.data.WriterT` values initialized with @@ -251,16 +260,16 @@ object Random { Random[F].mapK(IorT.liftK) /** - * [[Random]] instance built for `cats.data.ReaderWriterStateT` values + * [[Random]] instance built for `cats.data.IndexedReaderWriterStateT` values * initialized with any `F` data type that also implements `Random`. */ - implicit def catsReaderWriterStateTRandom[ + implicit def catsIndexedReaderWriterStateTRandom[ F[_]: Random: Applicative, E, L: Monoid, S - ]: Random[ReaderWriterStateT[F, E, L, S, *]] = - Random[F].mapK(ReaderWriterStateT.liftK) + ]: Random[IndexedReaderWriterStateT[F, E, L, S, S, *]] = + Random[F].mapK(IndexedReaderWriterStateT.liftK) /** * Creates Several Random Number Generators and equally