From 784a69738429dd09d7877871b31df5b48068f0e0 Mon Sep 17 00:00:00 2001 From: Itamar Ravid Date: Sat, 5 Aug 2017 23:54:25 +0300 Subject: [PATCH 1/9] Convert ReaderWriterStateT to IndexedReaderWriterStateT Resolves #1774. --- .../scala/cats/data/ReaderWriterStateT.scala | 341 +++++++++++------- core/src/main/scala/cats/data/package.scala | 12 +- .../cats/laws/discipline/Arbitrary.scala | 5 +- .../cats/tests/ReaderWriterStateTTests.scala | 111 ++++-- 4 files changed, 298 insertions(+), 171 deletions(-) diff --git a/core/src/main/scala/cats/data/ReaderWriterStateT.scala b/core/src/main/scala/cats/data/ReaderWriterStateT.scala index fdd352bfb8..12467816b8 100644 --- a/core/src/main/scala/cats/data/ReaderWriterStateT.scala +++ b/core/src/main/scala/cats/data/ReaderWriterStateT.scala @@ -1,59 +1,84 @@ package cats package data -import cats.functor.{ Contravariant, Profunctor } +import cats.functor.{ Bifunctor, Contravariant, Profunctor } import cats.syntax.either._ /** - * Represents a stateful computation in a context `F[_]`, over state `S`, with an initial environment `E`, - * an accumulated log `L` and a result `A`. + * Represents a stateful computation in a context `F[_]`, from state `SA` to state `SB`, + * with an initial environment `E`, an accumulated log `L` and a result `A`. * * In other words, it is a pre-baked stack of `[[ReaderT]][F, E, A]`, `[[WriterT]][F, L, A]` - * and `[[StateT]][F, S, A]`. + * and `[[IndexedStateT]][F, SA, SB, A]`. */ -final class ReaderWriterStateT[F[_], E, L, S, A](val runF: F[(E, S) => F[(L, S, A)]]) extends Serializable { +final class IndexedReaderWriterStateT[F[_], E, L, SA, SB, A](val runF: F[(E, SA) => F[(L, SB, A)]]) extends Serializable { /** - * Modify the initial environment using `f`. + * Modify the initial state using `f`. */ - def contramap[E0](f: E0 => E)(implicit F: Functor[F]): ReaderWriterStateT[F, E0, L, S, A] = - ReaderWriterStateT.applyF { - F.map(runF) { rwsa => - (e0: E0, s: S) => rwsa(f(e0), s) + def contramap[S0](f: S0 => SA)(implicit F: Functor[F]): IndexedReaderWriterStateT[F, E, L, S0, SB, A] = + IndexedReaderWriterStateT.applyF { + F.map(runF) { rwsfa => + (e: E, s0: S0) => rwsfa(e, f(s0)) } } /** - * Alias for [[contramap]]. - */ - def local[EE](f: EE => E)(implicit F: Functor[F]): ReaderWriterStateT[F, EE, L, S, A] = - contramap(f) + * Modify the initial environment using `f`. + * + * {{{ + * scala> import cats.implicits._ + * scala> type Env = String + * scala> type GlobalEnv = (Int, Env) + * scala> type Log = List[String] + * scala> val xLocal: IndexedReaderWriterStateT[Option, Env, Log, Int, Int, Int] = IndexedReaderWriterStateT.get + * scala> val xGlobal: IndexedReaderWriterStateT[Option, GlobalEnv, Log, Int, Int, Int] = xLocal.local(_._2) + * }}} + */ + def local[EE](f: EE => E)(implicit F: Functor[F]): IndexedReaderWriterStateT[F, EE, L, SA, SB, A] = + IndexedReaderWriterStateT.applyF { + F.map(runF) { rwsa => + (ee: EE, sa: SA) => rwsa(f(ee), sa) + } + } /** * Modify the result of the computation using `f`. */ - def map[B](f: A => B)(implicit F: Functor[F]): ReaderWriterStateT[F, E, L, S, B] = + def map[B](f: A => B)(implicit F: Functor[F]): IndexedReaderWriterStateT[F, E, L, SA, SB, B] = transform { (l, s, a) => (l, s, f(a)) } + /** + * Modify the resulting state using `f` and the resulting value using `g`. + */ + def bimap[SC, B](f: SB => SC, g: A => B)(implicit F: Functor[F]): IndexedReaderWriterStateT[F, E, L, SA, SC, B] = + transform { (l, s, a) => (l, f(s), g(a)) } + + /** + * Modify the initial state using `f` and the resulting state using `g`. + */ + def dimap[S0, S1](f: S0 => SA)(g: SB => S1)(implicit F: Functor[F]): IndexedReaderWriterStateT[F, E, L, S0, S1, A] = + contramap(f).modify(g) + /** * Modify the written log value using `f`. */ - def mapWritten[LL](f: L => LL)(implicit F: Functor[F]): ReaderWriterStateT[F, E, LL, S, A] = + def mapWritten[LL](f: L => LL)(implicit F: Functor[F]): IndexedReaderWriterStateT[F, E, LL, SA, SB, A] = transform { (l, s, a) => (f(l), s, a) } /** * Modify the result of the computation by feeding it into `f`, threading the state * through the resulting computation and combining the log values. */ - def flatMap[B](f: A => ReaderWriterStateT[F, E, L, S, B])( - implicit F: FlatMap[F], L: Semigroup[L]): ReaderWriterStateT[F, E, L, S, B] = - ReaderWriterStateT.applyF { + def flatMap[SC, B](f: A => IndexedReaderWriterStateT[F, E, L, SB, SC, B])( + implicit F: FlatMap[F], L: Semigroup[L]): IndexedReaderWriterStateT[F, E, L, SA, SC, B] = + IndexedReaderWriterStateT.applyF { F.map(runF) { rwsfa => - (e: E, s0: S) => - F.flatMap(rwsfa(e, s0)) { case (la, sa, a) => + (e: E, sa: SA) => + F.flatMap(rwsfa(e, sa)) { case (la, sb, a) => F.flatMap(f(a).runF) { rwsfb => - F.map(rwsfb(e, sa)) { case (lb, sb, b) => - (L.combine(la, lb), sb, b) + F.map(rwsfb(e, sb)) { case (lb, sc, b) => + (L.combine(la, lb), sc, b) } } } @@ -63,12 +88,12 @@ final class ReaderWriterStateT[F[_], E, L, S, A](val runF: F[(E, S) => F[(L, S, /** * Like [[map]], but allows the mapping function to return an effectful value. */ - def flatMapF[B](faf: A => F[B])(implicit F: FlatMap[F]): ReaderWriterStateT[F, E, L, S, B] = - ReaderWriterStateT.applyF { + def flatMapF[B](faf: A => F[B])(implicit F: FlatMap[F]): IndexedReaderWriterStateT[F, E, L, SA, SB, B] = + IndexedReaderWriterStateT.applyF { F.map(runF) { rwsfa => - (e: E, s: S) => - F.flatMap(rwsfa(e, s)) { case (l, s, a) => - F.map(faf(a))((l, s, _)) + (e: E, sa: SA) => + F.flatMap(rwsfa(e, sa)) { case (l, sb, a) => + F.map(faf(a))((l, sb, _)) } } } @@ -76,193 +101,235 @@ final class ReaderWriterStateT[F[_], E, L, S, A](val runF: F[(E, S) => F[(L, S, /** * Transform the resulting log, state and value using `f`. */ - def transform[LL, B](f: (L, S, A) => (LL, S, B))(implicit F: Functor[F]): ReaderWriterStateT[F, E, LL, S, B] = - ReaderWriterStateT.applyF { + def transform[LL, SC, B](f: (L, SB, A) => (LL, SC, B))(implicit F: Functor[F]): IndexedReaderWriterStateT[F, E, LL, SA, SC, B] = + IndexedReaderWriterStateT.applyF { F.map(runF) { rwsfa => - (e: E, s: S) => F.map(rwsfa(e, s)) { case (l, s, a) => - val (ll, sb, b) = f(l, s, a) - (ll, sb, b) + (e: E, s: SA) => F.map(rwsfa(e, s)) { case (l, sb, a) => + val (ll, sc, b) = f(l, sb, a) + (ll, sc, b) } } } /** * Like [[transform]], but allows the context to change from `F` to `G`. - */ - def transformF[G[_], LL, B](f: F[(L, S, A)] => G[(LL, S, B)])( - implicit F: Monad[F], G: Applicative[G]): ReaderWriterStateT[G, E, LL, S, B] = - ReaderWriterStateT.apply((e, s) => f(run(e, s))) + * + * {{{ + * scala> import cats.implicits._ + * scala> type ErrorOr[A] = Either[String, A] + * scala> type Env = String + * scala> type Log = List[String] + * scala> val xError: IndexedReaderWriterStateT[ErrorOr, Env, Log, Int, Int, Int] = IndexedReaderWriterStateT.get + * scala> val xOpt: IndexedReaderWriterStateT[Option, Env, Log, Int, Int, Int] = xError.transformF(_.toOption) + * scala> val input = 5 + * scala> xError.run("env", input) + * res0: ErrorOr[(Log, Int, Int)] = Right((List(),5,5)) + * scala> xOpt.run("env", 5) + * res1: Option[(Log, Int, Int)] = Some((List(),5,5)) + * }}} + */ + def transformF[G[_], LL, SC, B](f: F[(L, SB, A)] => G[(LL, SC, B)])( + implicit F: Monad[F], G: Applicative[G]): IndexedReaderWriterStateT[G, E, LL, SA, SC, B] = + IndexedReaderWriterStateT.apply((e, s) => f(run(e, s))) /** * Modify the resulting state. */ - def modify(f: S => S)(implicit F: Functor[F]): ReaderWriterStateT[F, E, L, S, A] = - transform { (l, s, a) => (l, f(s), a) } + def modify[SC](f: SB => SC)(implicit F: Functor[F]): IndexedReaderWriterStateT[F, E, L, SA, SC, A] = + transform { (l, sb, a) => (l, f(sb), a) } /** * Inspect a value from the input state, without modifying the state. */ - def inspect[B](f: S => B)(implicit F: Functor[F]): ReaderWriterStateT[F, E, L, S, B] = - transform { (l, s, a) => (l, s, f(s)) } + def inspect[B](f: SB => B)(implicit F: Functor[F]): IndexedReaderWriterStateT[F, E, L, SA, SB, B] = + transform { (l, sb, a) => (l, sb, f(sb)) } /** * Get the input state, without modifying it. */ - def get(implicit F: Functor[F]): ReaderWriterStateT[F, E, L, S, S] = + def get(implicit F: Functor[F]): IndexedReaderWriterStateT[F, E, L, SA, SB, SB] = inspect(identity) /** * Add a value to the log. */ - def tell(l: L)(implicit F: Functor[F], L: Semigroup[L]): ReaderWriterStateT[F, E, L, S, A] = + def tell(l: L)(implicit F: Functor[F], L: Semigroup[L]): IndexedReaderWriterStateT[F, E, L, SA, SB, A] = mapWritten(L.combine(_, l)) /** * Retrieve the value written to the log. */ - def written(implicit F: Functor[F]): ReaderWriterStateT[F, E, L, S, L] = - transform { (l, s, a) => (l, s, l) } + def written(implicit F: Functor[F]): IndexedReaderWriterStateT[F, E, L, SA, SB, L] = + transform { (l, sb, a) => (l, sb, l) } /** * Clear the log. */ - def reset(implicit F: Functor[F], L: Monoid[L]): ReaderWriterStateT[F, E, L, S, A] = + def reset(implicit F: Functor[F], L: Monoid[L]): IndexedReaderWriterStateT[F, E, L, SA, SB, A] = mapWritten(_ => L.empty) /** * Run the computation using the provided initial environment and state. */ - def run(env: E, initial: S)(implicit F: Monad[F]): F[(L, S, A)] = + def run(env: E, initial: SA)(implicit F: Monad[F]): F[(L, SB, A)] = F.flatMap(runF)(_.apply(env, initial)) /** * Run the computation using the provided environment and an empty state. */ - def runEmpty(env: E)(implicit F: Monad[F], S: Monoid[S]): F[(L, S, A)] = - run(env, S.empty) + def runEmpty(env: E)(implicit F: Monad[F], SA: Monoid[SA]): F[(L, SB, A)] = + run(env, SA.empty) /** * Like [[run]], but discards the final state and log. */ - def runA(env: E, initial: S)(implicit F: Monad[F]): F[A] = + def runA(env: E, initial: SA)(implicit F: Monad[F]): F[A] = F.map(run(env, initial))(_._3) /** * Like [[run]], but discards the final value and log. */ - def runS(env: E, initial: S)(implicit F: Monad[F]): F[S] = + def runS(env: E, initial: SA)(implicit F: Monad[F]): F[SB] = F.map(run(env, initial))(_._2) /** * Like [[run]], but discards the final state and value. */ - def runL(env: E, initial: S)(implicit F: Monad[F]): F[L] = + def runL(env: E, initial: SA)(implicit F: Monad[F]): F[L] = F.map(run(env, initial))(_._1) /** * Like [[runEmpty]], but discards the final state and log. */ - def runEmptyA(env: E)(implicit F: Monad[F], S: Monoid[S]): F[A] = - runA(env, S.empty) + def runEmptyA(env: E)(implicit F: Monad[F], SA: Monoid[SA]): F[A] = + runA(env, SA.empty) /** * Like [[runEmpty]], but discards the final value and log. */ - def runEmptyS(env: E)(implicit F: Monad[F], S: Monoid[S]): F[S] = - runS(env, S.empty) + def runEmptyS(env: E)(implicit F: Monad[F], SA: Monoid[SA]): F[SB] = + runS(env, SA.empty) /** * Like [[runEmpty]], but discards the final state and value. */ - def runEmptyL(env: E)(implicit F: Monad[F], S: Monoid[S]): F[L] = - runL(env, S.empty) + def runEmptyL(env: E)(implicit F: Monad[F], SA: Monoid[SA]): F[L] = + runL(env, SA.empty) } -object ReaderWriterStateT extends RWSTInstances { +private[data] sealed trait CommonIRWSTConstructors { /** - * Construct a new computation using the provided function. + * Return `a` and an empty log without modifying the input state. */ - def apply[F[_], E, L, S, A](runF: (E, S) => F[(L, S, A)])(implicit F: Applicative[F]): ReaderWriterStateT[F, E, L, S, A] = - new ReaderWriterStateT(F.pure(runF)) + def pure[F[_], E, L, S, A](a: A)(implicit F: Applicative[F], L: Monoid[L]): IndexedReaderWriterStateT[F, E, L, S, S, A] = + IndexedReaderWriterStateT((_, s) => F.pure((L.empty, s, a))) /** - * Like [[apply]], but using a function in a context `F`. + * Return an effectful `a` and an empty log without modifying the input state. */ - def applyF[F[_], E, L, S, A](runF: F[(E, S) => F[(L, S, A)]]): ReaderWriterStateT[F, E, L, S, A] = - new ReaderWriterStateT(runF) + def lift[F[_], E, L, S, A](fa: F[A])(implicit F: Applicative[F], L: Monoid[L]): IndexedReaderWriterStateT[F, E, L, S, S, A] = + IndexedReaderWriterStateT((_, s) => F.map(fa)((L.empty, s, _))) /** - * Return `a` and an empty log without modifying the input state. + * Inspect a value from the input state, without modifying the state. */ - def pure[F[_], E, L, S, A](a: A)(implicit F: Applicative[F], L: Monoid[L]): ReaderWriterStateT[F, E, L, S, A] = - ReaderWriterStateT((_, s) => F.pure((L.empty, s, a))) + def inspect[F[_], E, L, S, A](f: S => A)(implicit F: Applicative[F], L: Monoid[L]): IndexedReaderWriterStateT[F, E, L, S, S, A] = + IndexedReaderWriterStateT((_, s) => F.pure((L.empty, s, f(s)))) /** - * Return an effectful `a` and an empty log without modifying the input state. + * Like [[inspect]], but using an effectful function. */ - def lift[F[_], E, L, S, A](fa: F[A])(implicit F: Applicative[F], L: Monoid[L]): ReaderWriterStateT[F, E, L, S, A] = - ReaderWriterStateT((_, s) => F.map(fa)((L.empty, s, _))) + def inspectF[F[_], E, L, S, A](f: S => F[A])(implicit F: Applicative[F], L: Monoid[L]): IndexedReaderWriterStateT[F, E, L, S, S, A] = + IndexedReaderWriterStateT((_, s) => F.map(f(s))((L.empty, s, _))) /** - * Inspect a value from the input state, without modifying the state. + * Set the state to `s`. */ - def inspect[F[_], E, L, S, A](f: S => A)(implicit F: Applicative[F], L: Monoid[L]): ReaderWriterStateT[F, E, L, S, A] = - ReaderWriterStateT((_, s) => F.pure((L.empty, s, f(s)))) + def set[F[_], E, L, S](s: S)(implicit F: Applicative[F], L: Monoid[L]): IndexedReaderWriterStateT[F, E, L, S, S, Unit] = + IndexedReaderWriterStateT((_, _) => F.pure((L.empty, s, ()))) /** - * Like [[inspect]], but using an effectful function. + * Like [[set]], but using an effectful `S` value. */ - def inspectF[F[_], E, L, S, A](f: S => F[A])(implicit F: Applicative[F], L: Monoid[L]): ReaderWriterStateT[F, E, L, S, A] = - ReaderWriterStateT((_, s) => F.map(f(s))((L.empty, s, _))) + def setF[F[_], E, L, S](fs: F[S])(implicit F: Applicative[F], L: Monoid[L]): IndexedReaderWriterStateT[F, E, L, S, S, Unit] = + IndexedReaderWriterStateT((_, _) => F.map(fs)((L.empty, _, ()))) /** - * Modify the input state using `f`. + * Get the provided environment, without modifying the input state. */ - def modify[F[_], E, L, S](f: S => S)(implicit F: Applicative[F], L: Monoid[L]): ReaderWriterStateT[F, E, L, S, Unit] = - ReaderWriterStateT((_, s) => F.pure((L.empty, f(s), ()))) + def ask[F[_], E, L, S](implicit F: Applicative[F], L: Monoid[L]): IndexedReaderWriterStateT[F, E, L, S, S, E] = + IndexedReaderWriterStateT((e, s) => F.pure((L.empty, s, e))) /** - * Like [[modify]], but using an effectful function. + * Add a value to the log, without modifying the input state. */ - def modifyF[F[_], E, L, S](f: S => F[S])(implicit F: Applicative[F], L: Monoid[L]): ReaderWriterStateT[F, E, L, S, Unit] = - ReaderWriterStateT((_, s) => F.map(f(s))((L.empty, _, ()))) + def tell[F[_], E, L, S](l: L)(implicit F: Applicative[F]): IndexedReaderWriterStateT[F, E, L, S, S, Unit] = + IndexedReaderWriterStateT((_, s) => F.pure((l, s, ()))) + + /** + * Like [[tell]], but using an effectful `L` value. + */ + def tellF[F[_], E, L, S](fl: F[L])(implicit F: Applicative[F]): IndexedReaderWriterStateT[F, E, L, S, S, Unit] = + IndexedReaderWriterStateT((_, s) => F.map(fl)((_, s, ()))) /** * Return the input state without modifying it. */ - def get[F[_], E, L, S](implicit F: Applicative[F], L: Monoid[L]): ReaderWriterStateT[F, E, L, S, S] = - ReaderWriterStateT((_, s) => F.pure((L.empty, s, s))) + def get[F[_], E, L, S](implicit F: Applicative[F], L: Monoid[L]): IndexedReaderWriterStateT[F, E, L, S, S, S] = + IndexedReaderWriterStateT((_, s) => F.pure((L.empty, s, s))) +} +object IndexedReaderWriterStateT extends IRWSTInstances with CommonIRWSTConstructors { /** - * Set the state to `s`. + * Construct a new computation using the provided function. */ - def set[F[_], E, L, S](s: S)(implicit F: Applicative[F], L: Monoid[L]): ReaderWriterStateT[F, E, L, S, Unit] = - ReaderWriterStateT((_, _) => F.pure((L.empty, s, ()))) + def apply[F[_], E, L, SA, SB, A](runF: (E, SA) => F[(L, SB, A)])(implicit F: Applicative[F]): IndexedReaderWriterStateT[F, E, L, SA, SB, A] = + new IndexedReaderWriterStateT(F.pure(runF)) /** - * Like [[set]], but using an effectful `S` value. + * Like [[apply]], but using a function in a context `F`. */ - def setF[F[_], E, L, S](fs: F[S])(implicit F: Applicative[F], L: Monoid[L]): ReaderWriterStateT[F, E, L, S, Unit] = - ReaderWriterStateT((_, _) => F.map(fs)((L.empty, _, ()))) + def applyF[F[_], E, L, SA, SB, A](runF: F[(E, SA) => F[(L, SB, A)]]): IndexedReaderWriterStateT[F, E, L, SA, SB, A] = + new IndexedReaderWriterStateT(runF) /** - * Get the provided environment, without modifying the input state. + * Modify the input state using `f`. */ - def ask[F[_], E, L, S](implicit F: Applicative[F], L: Monoid[L]): ReaderWriterStateT[F, E, L, S, E] = - ReaderWriterStateT((e, s) => F.pure((L.empty, s, e))) + def modify[F[_], E, L, SA, SB](f: SA => SB)(implicit F: Applicative[F], L: Monoid[L]): IndexedReaderWriterStateT[F, E, L, SA, SB, Unit] = + IndexedReaderWriterStateT((_, s) => F.pure((L.empty, f(s), ()))) /** - * Add a value to the log, without modifying the input state. + * Like [[modify]], but using an effectful function. */ - def tell[F[_], E, L, S](l: L)(implicit F: Applicative[F]): ReaderWriterStateT[F, E, L, S, Unit] = - ReaderWriterStateT((_, s) => F.pure((l, s, ()))) + def modifyF[F[_], E, L, SA, SB](f: SA => F[SB])(implicit F: Applicative[F], L: Monoid[L]): IndexedReaderWriterStateT[F, E, L, SA, SB, Unit] = + IndexedReaderWriterStateT((_, s) => F.map(f(s))((L.empty, _, ()))) +} +private[data] abstract class RWSTFunctions extends CommonIRWSTConstructors { /** - * Like [[tell]], but using an effectful `L` value. + * Construct a new computation using the provided function. + */ + def apply[F[_], E, L, S, A](runF: (E, S) => F[(L, S, A)])(implicit F: Applicative[F]): ReaderWriterStateT[F, E, L, S, A] = + new IndexedReaderWriterStateT(F.pure(runF)) + + /** + * Like [[apply]], but using a function in a context `F`. + */ + def applyF[F[_], E, L, S, A](runF: F[(E, S) => F[(L, S, A)]]): ReaderWriterStateT[F, E, L, S, A] = + new IndexedReaderWriterStateT(runF) + + /** + * Modify the input state using `f`. + */ + def modify[F[_], E, L, S](f: S => S)(implicit F: Applicative[F], L: Monoid[L]): ReaderWriterStateT[F, E, L, S, Unit] = + ReaderWriterStateT((_, s) => F.pure((L.empty, f(s), ()))) + + /** + * Like [[modify]], but using an effectful function. */ - def tellF[F[_], E, L, S](fl: F[L])(implicit F: Applicative[F]): ReaderWriterStateT[F, E, L, S, Unit] = - ReaderWriterStateT((_, s) => F.map(fl)((_, s, ()))) + def modifyF[F[_], E, L, S](f: S => F[S])(implicit F: Applicative[F], L: Monoid[L]): ReaderWriterStateT[F, E, L, S, Unit] = + ReaderWriterStateT((_, s) => F.map(f(s))((L.empty, _, ()))) } /** @@ -318,18 +385,23 @@ private[data] abstract class RWSFunctions { ReaderWriterStateT.tell(l) } -private[data] sealed trait RWSTInstances extends RWSTInstances1 { - implicit def catsDataProfunctorForRWST[F[_], L, S](implicit F0: Functor[F]): Profunctor[ReaderWriterStateT[F, ?, L, S, ?]] = - new RWSTProfunctor[F, L, S] { +private[data] sealed trait IRWSTInstances extends IRWSTInstances1 { + implicit def catsDataProfunctorForIRWST[F[_], E, L, T](implicit F0: Functor[F]): Profunctor[IndexedReaderWriterStateT[F, E, L, ?, ?, T]] = + new IRWSTProfunctor[F, E, L, T] { implicit def F: Functor[F] = F0 } - implicit def catsDataContravariantForRWST[F[_], L, S, A](implicit F0: Functor[F]): Contravariant[ReaderWriterStateT[F, ?, L, S, A]] = - new RWSTContravariant[F, L, S, A] { + implicit def catsDataBifunctorForIRWST[F[_], E, L, SA](implicit F0: Functor[F]): Bifunctor[IndexedReaderWriterStateT[F, E, L, SA, ?, ?]] = + new IRWSTBifunctor[F, E, L, SA] { implicit def F: Functor[F] = F0 } - implicit def catsDataMonadErrorForRWST[F[_], E, L, S, R](implicit F0: MonadError[F, R], L0: Monoid[L]): MonadError[ReaderWriterStateT[F, E, L, S, ?], R] = + implicit def catsDataContravariantForIRWST[F[_], E, L, SB, T](implicit F0: Functor[F]): Contravariant[IndexedReaderWriterStateT[F, E, L, ?, SB, T]] = + new IRWSTContravariant[F, E, L, SB, T] { + implicit def F: Functor[F] = F0 + } + + implicit def catsDataMonadErrorForIRWST[F[_], E, L, S, R](implicit F0: MonadError[F, R], L0: Monoid[L]): MonadError[IndexedReaderWriterStateT[F, E, L, S, S, ?], R] = new RWSTMonadError[F, E, L, S, R] { implicit def F: MonadError[F, R] = F0 implicit def L: Monoid[L] = L0 @@ -337,7 +409,7 @@ private[data] sealed trait RWSTInstances extends RWSTInstances1 { } -private[data] sealed trait RWSTInstances1 extends RWSTInstances2 { +private[data] sealed trait IRWSTInstances1 extends IRWSTInstances2 { implicit def catsDataMonadForRWST[F[_], E, L, S](implicit F0: Monad[F], L0: Monoid[L]): Monad[ReaderWriterStateT[F, E, L, S, ?]] = new RWSTMonad[F, E, L, S] { implicit def F: Monad[F] = F0 @@ -345,9 +417,9 @@ private[data] sealed trait RWSTInstances1 extends RWSTInstances2 { } } -private[data] sealed trait RWSTInstances2 extends RWSTInstances3 { - implicit def catsDataAlternativeForRWST[F[_], E, L, S]( - implicit FM: Monad[F], FA: Alternative[F], L0: Monoid[L]): Alternative[ReaderWriterStateT[F, E, L, S, ?]] = +private[data] sealed trait IRWSTInstances2 extends IRWSTInstances3 { + implicit def catsDataAlternativeForIRWST[F[_], E, L, S](implicit FM: Monad[F], FA: Alternative[F], + L0: Monoid[L]): Alternative[IndexedReaderWriterStateT[F, E, L, S, S, ?]] = new RWSTAlternative[F, E, L, S] { implicit def G: Alternative[F] = FA implicit def F: Monad[F] = FM @@ -355,41 +427,49 @@ private[data] sealed trait RWSTInstances2 extends RWSTInstances3 { } } -private[data] sealed trait RWSTInstances3 { - implicit def catsDataSemigroupKForRWST[F[_], E, L, S]( - implicit F0: Monad[F], G0: SemigroupK[F]): SemigroupK[ReaderWriterStateT[F, E, L, S, ?]] = - new RWSTSemigroupK[F, E, L, S] { +private[data] sealed trait IRWSTInstances3 { + implicit def catsDataSemigroupKForIRWST[F[_], E, L, SA, SB](implicit F0: Monad[F], + G0: SemigroupK[F]): SemigroupK[IndexedReaderWriterStateT[F, E, L, SA, SB, ?]] = + new IRWSTSemigroupK[F, E, L, SA, SB] { implicit def F: Monad[F] = F0 implicit def G: SemigroupK[F] = G0 } - implicit def catsDataFunctorForRWST[F[_], E, L, S](implicit F0: Functor[F]): Functor[ReaderWriterStateT[F, E, L, S, ?]] = - new RWSTFunctor[F, E, L, S] { + + implicit def catsDataFunctorForIRWST[F[_], E, L, SA, SB](implicit F0: Functor[F]): Functor[IndexedReaderWriterStateT[F, E, L, SA, SB, ?]] = + new IRWSTFunctor[F, E, L, SA, SB] { implicit def F: Functor[F] = F0 } } -private[data] sealed trait RWSTFunctor[F[_], E, L, S] extends Functor[ReaderWriterStateT[F, E, L, S, ?]] { +private[data] sealed trait IRWSTFunctor[F[_], E, L, SA, SB] extends Functor[IndexedReaderWriterStateT[F, E, L, SA, SB, ?]] { implicit def F: Functor[F] - override def map[A, B](fa: ReaderWriterStateT[F, E, L, S, A])(f: A => B): ReaderWriterStateT[F, E, L, S, B] = + override def map[A, B](fa: IndexedReaderWriterStateT[F, E, L, SA, SB, A])(f: A => B): IndexedReaderWriterStateT[F, E, L, SA, SB, B] = fa.map(f) } -private[data] sealed trait RWSTContravariant[F[_], L, S, T] extends Contravariant[ReaderWriterStateT[F, ?, L, S, T]] { +private[data] sealed trait IRWSTContravariant[F[_], E, L, SB, T] extends Contravariant[IndexedReaderWriterStateT[F, E, L, ?, SB, T]] { implicit def F: Functor[F] - override def contramap[A, B](fa: ReaderWriterStateT[F, A, L, S, T])(f: B => A): ReaderWriterStateT[F, B, L, S, T] = + override def contramap[A, B](fa: IndexedReaderWriterStateT[F, E, L, A, SB, T])(f: B => A): IndexedReaderWriterStateT[F, E, L, B, SB, T] = fa.contramap(f) } -private[data] sealed trait RWSTProfunctor[F[_], L, S] extends Profunctor[ReaderWriterStateT[F, ?, L, S, ?]] { +private[data] sealed trait IRWSTProfunctor[F[_], E, L, T] extends Profunctor[IndexedReaderWriterStateT[F, E, L, ?, ?, T]] { implicit def F: Functor[F] - override def dimap[A, B, C, D](fab: ReaderWriterStateT[F, A, L, S, B])(f: C => A)(g: B => D): ReaderWriterStateT[F, C, L, S, D] = - fab.contramap(f).map(g) + override def dimap[A, B, C, D](fab: IndexedReaderWriterStateT[F, E, L, A, B, T])(f: C => A)(g: B => D): IndexedReaderWriterStateT[F, E, L, C, D, T] = + fab.dimap(f)(g) } -private[data] sealed trait RWSTMonad[F[_], E, L, S] extends Monad[ReaderWriterStateT[F, E, L, S, ?]] with RWSTFunctor[F, E, L, S] { +private[data] sealed trait IRWSTBifunctor[F[_], E, L, SA] extends Bifunctor[IndexedReaderWriterStateT[F, E, L, SA, ?, ?]] { + implicit def F: Functor[F] + + override def bimap[A, B, C, D](fab: IndexedReaderWriterStateT[F, E, L, SA, A, B])(f: A => C, g: B => D): IndexedReaderWriterStateT[F, E, L, SA, C, D] = + fab.bimap(f, g) +} + +private[data] sealed trait RWSTMonad[F[_], E, L, S] extends Monad[ReaderWriterStateT[F, E, L, S, ?]] with IRWSTFunctor[F, E, L, S, S] { implicit def F: Monad[F] implicit def L: Monoid[L] @@ -409,19 +489,20 @@ private[data] sealed trait RWSTMonad[F[_], E, L, S] extends Monad[ReaderWriterSt } } -private[data] sealed trait RWSTSemigroupK[F[_], E, L, S] extends SemigroupK[ReaderWriterStateT[F, E, L, S, ?]] { +private[data] sealed trait IRWSTSemigroupK[F[_], E, L, SA, SB] extends SemigroupK[IndexedReaderWriterStateT[F, E, L, SA, SB, ?]] { implicit def F: Monad[F] implicit def G: SemigroupK[F] - def combineK[A](x: ReaderWriterStateT[F, E, L, S, A], y: ReaderWriterStateT[F, E, L, S, A]): ReaderWriterStateT[F, E, L, S, A] = - ReaderWriterStateT { (e, s) => - G.combineK(x.run(e, s), y.run(e, s)) + def combineK[A](x: IndexedReaderWriterStateT[F, E, L, SA, SB, A], + y: IndexedReaderWriterStateT[F, E, L, SA, SB, A]): IndexedReaderWriterStateT[F, E, L, SA, SB, A] = + IndexedReaderWriterStateT { (e, sa) => + G.combineK(x.run(e, sa), y.run(e, sa)) } } private[data] sealed trait RWSTAlternative[F[_], E, L, S] - extends Alternative[ReaderWriterStateT[F, E, L, S, ?]] with RWSTFunctor[F, E, L, S] - with RWSTSemigroupK[F, E, L, S] { + extends Alternative[ReaderWriterStateT[F, E, L, S, ?]] with IRWSTFunctor[F, E, L, S, S] + with IRWSTSemigroupK[F, E, L, S, S] { implicit def F: Monad[F] override def G: Alternative[F] diff --git a/core/src/main/scala/cats/data/package.scala b/core/src/main/scala/cats/data/package.scala index 0d82370fb3..59775d7161 100644 --- a/core/src/main/scala/cats/data/package.scala +++ b/core/src/main/scala/cats/data/package.scala @@ -41,7 +41,17 @@ package object data { type State[S, A] = StateT[Eval, S, A] object State extends StateFunctions - type RWST[F[_], E, S, L, A] = ReaderWriterStateT[F, E, S, L, A] + type IRWST[F[_], E, L, SA, SB, A] = IndexedReaderWriterStateT[F, E, L, SA, SB, A] + val IRWST = IndexedReaderWriterStateT + + /** + * Represents a stateful computation in a context `F[_]`, over state `S`, with an + * initial environment `E`, an accumulated log `L` and a result `A`. + */ + type ReaderWriterStateT[F[_], E, L, S, A] = IndexedReaderWriterStateT[F, E, L, S, S, A] + object ReaderWriterStateT extends RWSTFunctions + + type RWST[F[_], E, L, S, A] = ReaderWriterStateT[F, E, L, S, A] val RWST = ReaderWriterStateT type ReaderWriterState[E, L, S, A] = ReaderWriterStateT[Eval, E, L, S, A] diff --git a/laws/src/main/scala/cats/laws/discipline/Arbitrary.scala b/laws/src/main/scala/cats/laws/discipline/Arbitrary.scala index 764aa8e340..679d2028a5 100644 --- a/laws/src/main/scala/cats/laws/discipline/Arbitrary.scala +++ b/laws/src/main/scala/cats/laws/discipline/Arbitrary.scala @@ -174,8 +174,9 @@ object arbitrary extends ArbitraryInstances0 { implicit def catsLawArbitraryForCokleisliId[A: Arbitrary: Cogen, B: Arbitrary]: Arbitrary[Cokleisli[Id, A, B]] = catsLawsArbitraryForCokleisli[Id, A, B] - implicit def catsLawsArbitraryForReaderWriterStateT[F[_]: Applicative, E, L, S, A](implicit F: Arbitrary[(E, S) => F[(L, S, A)]]): Arbitrary[ReaderWriterStateT[F, E, L, S, A]] = - Arbitrary(F.arbitrary.map(ReaderWriterStateT(_))) + implicit def catsLawsArbitraryForIRWST[F[_]: Applicative, E, L, SA, SB, A](implicit + F: Arbitrary[(E, SA) => F[(L, SB, A)]]): Arbitrary[IndexedReaderWriterStateT[F, E, L, SA, SB, A]] = + Arbitrary(F.arbitrary.map(IndexedReaderWriterStateT(_))) } diff --git a/tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala b/tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala index de379464a1..403408dd2b 100644 --- a/tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala +++ b/tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala @@ -1,8 +1,8 @@ package cats package tests -import cats.data.{ ReaderWriterStateT, ReaderWriterState, EitherT } -import cats.functor.{ Contravariant, Profunctor } +import cats.data.{ IRWST, IndexedReaderWriterStateT, ReaderWriterStateT, ReaderWriterState, EitherT } +import cats.functor.{ Contravariant, Bifunctor, Profunctor } import cats.laws.discipline._ import cats.laws.discipline.eq._ import cats.laws.discipline.arbitrary._ @@ -46,21 +46,14 @@ class ReaderWriterStateTTests extends CatsSuite { } } - test("local is consistent with contramap") { - forAll { (context: Int, initial: Int, f: Int => String) => - val rwsa = ReaderWriterState.pure[String, Unit, Int, Unit](()).contramap(f).flatMap(_ => ReaderWriterState.ask) - val rwsb = ReaderWriterState.pure[String, Unit, Int, Unit](()).local(f).flatMap(_ => ReaderWriterState.ask) - - rwsa.runA(context, initial) should === (rwsb.runA(context, initial)) - } - } - - test("ReaderWriterState.pure and ReaderWriterStateT.pure are consistent") { + test("ReaderWriterState.pure, ReaderWriterStateT.pure and IndexedReaderWriterStateT.pure are consistent") { forAll { (value: Int) => val rws: ReaderWriterState[String, Vector[String], Int, Int] = ReaderWriterState.pure(value) val rwst: ReaderWriterState[String, Vector[String], Int, Int] = ReaderWriterStateT.pure(value) + val irwst: ReaderWriterState[String, Vector[String], Int, Int] = IndexedReaderWriterStateT.pure(value) rws should === (rwst) + rwst should === (irwst) } } @@ -71,16 +64,27 @@ class ReaderWriterStateTTests extends CatsSuite { } } - test("ReaderWriterState.get and ReaderWriterStateT.get are consistent") { + test("ReaderWriterState.get, ReaderWriterStateT.get and IndexedReaderWriterStateT.get are consistent") { forAll { (initial: Int) => val rws: ReaderWriterState[String, Vector[String], Int, Int] = ReaderWriterState.get val rwst: ReaderWriterState[String, Vector[String], Int, Int] = ReaderWriterStateT.get + val irwst: ReaderWriterState[String, Vector[String], Int, Int] = IndexedReaderWriterStateT.get rws should === (rwst) + rwst should === (irwst) } } test("ReaderWriterState.get and instance get are consistent") { + forAll { (initial: Int) => + val singleton = ReaderWriterState.get[String, String, Int] + val instance = ReaderWriterState.pure[String, String, Int, Unit](()).get + + singleton should === (instance) + } + } + + test("ReaderWriterState.inspect and instance inspect are consistent") { forAll { (initial: Int) => val singleton = ReaderWriterState.inspect[String, String, Int, String](_.toString) val instance = ReaderWriterState.pure[String, String, Int, Unit](()).inspect(_.toString) @@ -89,84 +93,102 @@ class ReaderWriterStateTTests extends CatsSuite { } } - test("ReaderWriterState.inspect and ReaderWriterStateT.inspect are consistent") { + test("ReaderWriterState.inspect, ReaderWriterStateT.inspect and IndexedReaderWriterStateT.inspect are consistent") { forAll { (f: Int => Int) => val rws: ReaderWriterState[String, Vector[String], Int, Int] = ReaderWriterState.inspect(f) val rwst: ReaderWriterState[String, Vector[String], Int, Int] = ReaderWriterStateT.inspect(f) + val irwst: ReaderWriterState[String, Vector[String], Int, Int] = IndexedReaderWriterStateT.inspect(f) rws should === (rwst) + rwst should === (irwst) } } - test("ReaderWriterState.inspect and ReaderWriterStateT.inspectF are consistent") { + test("ReaderWriterState.inspect, ReaderWriterStateT.inspectF and IndexedReaderWriterStateT.inspectF are consistent") { forAll { (f: Int => Int) => val rws: ReaderWriterState[String, String, Int, Int] = ReaderWriterState.inspect(f) val rwst: ReaderWriterState[String, String, Int, Int] = ReaderWriterStateT.inspectF(f.andThen(Eval.now)) + val irwst: ReaderWriterState[String, String, Int, Int] = IndexedReaderWriterStateT.inspectF(f.andThen(Eval.now)) rws should === (rwst) + rwst should === (irwst) } } - test("ReaderWriterState.modify and ReaderWriterStateT.modify are consistent") { + test("ReaderWriterState.modify, ReaderWriterStateT.modify and IndexedReaderWriterStateT.modify are consistent") { forAll { (f: Int => Int) => val rws: ReaderWriterState[String, Vector[String], Int, Unit] = ReaderWriterState.modify(f) val rwst: ReaderWriterState[String, Vector[String], Int, Unit] = ReaderWriterStateT.modify(f) + val irwst: ReaderWriterState[String, Vector[String], Int, Unit] = IndexedReaderWriterStateT.modify(f) rws should === (rwst) + rwst should === (irwst) } } - test("ReaderWriterState.modify and ReaderWriterStateT.modifyF are consistent") { + test("ReaderWriterState.modify, ReaderWriterStateT.modifyF and IndexedReaderWriterStateT.modifyF are consistent") { forAll { (f: Int => Int) => val rws: ReaderWriterState[String, Vector[String], Int, Unit] = ReaderWriterState.modify(f) val rwst: ReaderWriterState[String, Vector[String], Int, Unit] = ReaderWriterStateT.modifyF(f.andThen(Eval.now)) + val irwst: ReaderWriterState[String, Vector[String], Int, Unit] = IndexedReaderWriterStateT.modifyF(f.andThen(Eval.now)) rws should === (rwst) + rwst should === (irwst) } } - test("ReaderWriterState.pure and ReaderWriterStateT.lift are consistent") { + test("ReaderWriterState.pure, ReaderWriterStateT.lift and IndexedReaderWriterStateT.lift are consistent") { forAll { (value: Int) => val rws: ReaderWriterState[String, Vector[String], Int, Int] = ReaderWriterState.pure(value) val rwst: ReaderWriterState[String, Vector[String], Int, Int] = ReaderWriterStateT.lift(Eval.now(value)) + val irwst: ReaderWriterState[String, Vector[String], Int, Int] = IndexedReaderWriterStateT.lift(Eval.now(value)) rws should === (rwst) + rwst should === (irwst) } } - test("ReaderWriterState.set and ReaderWriterStateT.set are consistent") { + test("ReaderWriterState.set, ReaderWriterStateT.set and IndexedReaderWriterStateT.set are consistent") { forAll { (next: Int) => val rws: ReaderWriterState[String, Vector[String], Int, Unit] = ReaderWriterState.set(next) val rwst: ReaderWriterState[String, Vector[String], Int, Unit] = ReaderWriterStateT.set(next) + val irwst: ReaderWriterState[String, Vector[String], Int, Unit] = IndexedReaderWriterStateT.set(next) rws should === (rwst) + rwst should === (irwst) } } - test("ReaderWriterState.set and ReaderWriterStateT.setF are consistent") { + test("ReaderWriterState.set, ReaderWriterStateT.setF and IndexedReaderWriterStateT.setF are consistent") { forAll { (next: Int) => val rws: ReaderWriterState[String, Vector[String], Int, Unit] = ReaderWriterState.set(next) val rwst: ReaderWriterState[String, Vector[String], Int, Unit] = ReaderWriterStateT.setF(Eval.now(next)) + val irwst: ReaderWriterState[String, Vector[String], Int, Unit] = IndexedReaderWriterStateT.setF(Eval.now(next)) rws should === (rwst) + rwst should === (irwst) } } - test("ReaderWriterState.tell and ReaderWriterStateT.tell are consistent") { + test("ReaderWriterState.tell, ReaderWriterStateT.tell and IndexedReaderWriterStateT.tell are consistent") { forAll { (log: String) => val rws: ReaderWriterState[String, String, Int, Unit] = ReaderWriterState.tell(log) val rwst: ReaderWriterState[String, String, Int, Unit] = ReaderWriterStateT.tell(log) + val irwst: ReaderWriterState[String, String, Int, Unit] = IndexedReaderWriterStateT.tell(log) rws should === (rwst) + rwst should === (irwst) } } - test("ReaderWriterState.tell and ReaderWriterStateT.tellF are consistent") { + test("ReaderWriterState.tell, ReaderWriterStateT.tellF and IndexedReaderWriterStateT.tellF are consistent") { forAll { (log: String) => val rws: ReaderWriterState[String, String, Int, Unit] = ReaderWriterState.tell(log) val rwst: ReaderWriterState[String, String, Int, Unit] = ReaderWriterStateT.tellF(Eval.now(log)) + val irwst: ReaderWriterState[String, String, Int, Unit] = IndexedReaderWriterStateT.tellF(Eval.now(log)) rws should === (rwst) + rwst should === (irwst) } } @@ -280,26 +302,39 @@ class ReaderWriterStateTTests extends CatsSuite { } implicit val iso = CartesianTests.Isomorphisms - .invariant[ReaderWriterStateT[ListWrapper, String, String, Int, ?]](ReaderWriterStateT.catsDataFunctorForRWST(ListWrapper.functor)) + .invariant[IndexedReaderWriterStateT[ListWrapper, String, String, Int, String, ?]](IndexedReaderWriterStateT.catsDataFunctorForIRWST(ListWrapper.functor)) { implicit val F: Monad[ListWrapper] = ListWrapper.monad - checkAll("ReaderWriterStateT[ListWrapper, String, String, Int, Int]", - FunctorTests[ReaderWriterStateT[ListWrapper, String, String, Int, ?]].functor[Int, Int, Int]) - checkAll("Functor[ReaderWriterStateT[ListWrapper, String, String, Int, ?]]", - SerializableTests.serializable(Functor[ReaderWriterStateT[ListWrapper, String, String, Int, ?]])) + checkAll("IndexedReaderWriterStateT[ListWrapper, String, String, Int, String, Int]", + FunctorTests[IndexedReaderWriterStateT[ListWrapper, String, String, Int, String, ?]].functor[Int, Int, Int]) + checkAll("Functor[IndexedReaderWriterStateT[ListWrapper, String, String, Int, String, ?]]", + SerializableTests.serializable(Functor[IndexedReaderWriterStateT[ListWrapper, String, String, Int, String, ?]])) - checkAll("ReaderWriterStateT[ListWrapper, String, String, Int, Int]", - ContravariantTests[ReaderWriterStateT[ListWrapper, ?, String, Int, Int]].contravariant[String, String, String]) - checkAll("Contravariant[ReaderWriterStateT[ListWrapper, ?, String, Int, Int]]", - SerializableTests.serializable(Contravariant[ReaderWriterStateT[ListWrapper, ?, String, Int, Int]])) + checkAll("IndexedReaderWriterStateT[ListWrapper, String, String, String, Int, Int]", + ContravariantTests[IndexedReaderWriterStateT[ListWrapper, String, String, ?, Int, Int]].contravariant[String, String, String]) + checkAll("Contravariant[IndexedReaderWriterStateT[ListWrapper, String, String, ?, Int, Int]]", + SerializableTests.serializable(Contravariant[IndexedReaderWriterStateT[ListWrapper, String, String, ?, Int, Int]])) + + checkAll("IndexedReaderWriterStateT[ListWrapper, String, String, Int, String, Int]", + ProfunctorTests[IndexedReaderWriterStateT[ListWrapper, String, String, ?, ?, Int]].profunctor[Int, Int, Int, String, String, String]) + checkAll("Profunctor[IndexedReaderWriterStateT[ListWrapper, String, String, ?, ?, Int]]", + SerializableTests.serializable(Profunctor[IndexedReaderWriterStateT[ListWrapper, String, String, ?, ?, Int]])) + + checkAll("IndexedReaderWriterStateT[ListWrapper, String, String, Int, Int, String]", + BifunctorTests[IndexedReaderWriterStateT[ListWrapper, String, String, Int, ?, ?]].bifunctor[Int, Int, Int, String, String, String]) + checkAll("Bifunctor[IndexedReaderWriterStateT[ListWrapper, String, String, Int, ?, ?]]", + SerializableTests.serializable(Bifunctor[IndexedReaderWriterStateT[ListWrapper, String, String, Int, ?, ?]])) + } + + { + implicit val G: Monad[ListWrapper] = ListWrapper.monad - checkAll("ReaderWriterStateT[ListWrapper, Int, String, Int, Int]", - ProfunctorTests[ReaderWriterStateT[ListWrapper, ?, String, Int, ?]].profunctor[Int, Int, Int, Int, Int, Int]) - checkAll("Profunctor[ReaderWriterStateT[ListWrapper, ?, String, Int, ?]]", - SerializableTests.serializable(Profunctor[ReaderWriterStateT[ListWrapper, ?, String, Int, ?]])) + val SA = IRWST.catsDataAlternativeForIRWST[ListWrapper, String, String, Int](ListWrapper.monad, ListWrapper.alternative, Monoid[String]) + checkAll("IndexedReaderWriterStateT[ListWrapper, String, String, Int, Int, Int]", AlternativeTests[IRWST[ListWrapper, String, String, Int, Int, ?]](SA).monoidK[Int]) + checkAll("Alternative[IndexedReaderWriterStateT[ListWrapper, String, String, Int, Int, ?]]", SerializableTests.serializable(SA)) } { @@ -349,9 +384,9 @@ object ReaderWriterStateTTests { ReaderWriterState { (context, state) => ((), state + i, state + i) } } - implicit def RWSTEq[F[_], E, L, S, A](implicit S: Arbitrary[S], E: Arbitrary[E], FLSA: Eq[F[(L, S, A)]], - F: Monad[F]): Eq[ReaderWriterStateT[F, E, L, S, A]] = - Eq.by[ReaderWriterStateT[F, E, L, S, A], (E, S) => F[(L, S, A)]] { state => + implicit def IRWSTEq[F[_], E, L, SA, SB, A](implicit SA: Arbitrary[SA], SB: Arbitrary[SB], E: Arbitrary[E], + FLSB: Eq[F[(L, SB, A)]], F: Monad[F]): Eq[IndexedReaderWriterStateT[F, E, L, SA, SB, A]] = + Eq.by[IndexedReaderWriterStateT[F, E, L, SA, SB, A], (E, SA) => F[(L, SB, A)]] { state => (e, s) => state.run(e, s) } } From 23ab7acd0c80f63cdab0e35182575ec4d5b87aec Mon Sep 17 00:00:00 2001 From: Itamar Ravid Date: Wed, 9 Aug 2017 00:21:21 +0300 Subject: [PATCH 2/9] Add transformS to IndexedReaderWriterStateT Resolves #1786. --- .../scala/cats/data/ReaderWriterStateT.scala | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/core/src/main/scala/cats/data/ReaderWriterStateT.scala b/core/src/main/scala/cats/data/ReaderWriterStateT.scala index 12467816b8..c66823abcc 100644 --- a/core/src/main/scala/cats/data/ReaderWriterStateT.scala +++ b/core/src/main/scala/cats/data/ReaderWriterStateT.scala @@ -132,6 +132,33 @@ final class IndexedReaderWriterStateT[F[_], E, L, SA, SB, A](val runF: F[(E, SA) implicit F: Monad[F], G: Applicative[G]): IndexedReaderWriterStateT[G, E, LL, SA, SC, B] = IndexedReaderWriterStateT.apply((e, s) => f(run(e, s))) + /** + * Transform the state used. See [[StateT]] for more details. + * + * {{{ + * scala> import cats.implicits._ // needed for StateT.apply + * scala> type Env = String + * scala> type Log = List[String] + * scala> type S[SA, SB, A] = IndexedReaderWriterStateT[Option, Env, Log, SA, SB, A] + * scala> type GlobalEnv = (Int, String) + * scala> val x: S[Int, Int, Double] = IndexedReaderWriterStateT((env: Env, x: Int) => Option(("Addition" :: Nil, x + 1, x.toDouble))) + * scala> val xt: S[GlobalEnv, GlobalEnv, Double] = x.transformS[GlobalEnv](_._1, (t, i) => (i, t._2)) + * scala> val input = 5 + * scala> x.run("env", input) + * res0: Option[(Log, Int, Double)] = Some((List(Addition),6,5.0)) + * scala> xt.run("env", (input, "hello")) + * res1: Option[(Log, GlobalEnv, Double)] = Some((List(Addition),(6,hello),5.0)) + * }}} + */ + def transformS[R](f: R => SA, g: (R, SB) => R)(implicit F: Functor[F]): IndexedReaderWriterStateT[F, E, L, R, R, A] = + IndexedReaderWriterStateT.applyF { + F.map(runF) { rwsfa => + (e: E, r: R) => F.map(rwsfa(e, f(r))) { case (l, sb, a) => + (l, g(r, sb), a) + } + } + } + /** * Modify the resulting state. From 9d86f10181a5a3f30fe475c18b9d196de2b152f3 Mon Sep 17 00:00:00 2001 From: Itamar Ravid Date: Wed, 9 Aug 2017 01:05:51 +0300 Subject: [PATCH 3/9] Temporarily modify scaladoc to avoid build failures --- core/src/main/scala/cats/data/ReaderWriterStateT.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/data/ReaderWriterStateT.scala b/core/src/main/scala/cats/data/ReaderWriterStateT.scala index c66823abcc..4dad556e51 100644 --- a/core/src/main/scala/cats/data/ReaderWriterStateT.scala +++ b/core/src/main/scala/cats/data/ReaderWriterStateT.scala @@ -9,7 +9,7 @@ import cats.syntax.either._ * with an initial environment `E`, an accumulated log `L` and a result `A`. * * In other words, it is a pre-baked stack of `[[ReaderT]][F, E, A]`, `[[WriterT]][F, L, A]` - * and `[[IndexedStateT]][F, SA, SB, A]`. + * and `IndexedStateT[F, SA, SB, A]`. */ final class IndexedReaderWriterStateT[F[_], E, L, SA, SB, A](val runF: F[(E, SA) => F[(L, SB, A)]]) extends Serializable { From 18ae2180bf83ffa09945ba63fbf73cc85c5710b6 Mon Sep 17 00:00:00 2001 From: Itamar Ravid Date: Fri, 1 Sep 2017 10:55:30 +0300 Subject: [PATCH 4/9] Convert instance traits to abstract classes --- .../scala/cats/data/ReaderWriterStateT.scala | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/core/src/main/scala/cats/data/ReaderWriterStateT.scala b/core/src/main/scala/cats/data/ReaderWriterStateT.scala index 4dad556e51..8dcd5a60fd 100644 --- a/core/src/main/scala/cats/data/ReaderWriterStateT.scala +++ b/core/src/main/scala/cats/data/ReaderWriterStateT.scala @@ -412,7 +412,7 @@ private[data] abstract class RWSFunctions { ReaderWriterStateT.tell(l) } -private[data] sealed trait IRWSTInstances extends IRWSTInstances1 { +private[data] sealed abstract class IRWSTInstances extends IRWSTInstances1 { implicit def catsDataProfunctorForIRWST[F[_], E, L, T](implicit F0: Functor[F]): Profunctor[IndexedReaderWriterStateT[F, E, L, ?, ?, T]] = new IRWSTProfunctor[F, E, L, T] { implicit def F: Functor[F] = F0 @@ -436,7 +436,7 @@ private[data] sealed trait IRWSTInstances extends IRWSTInstances1 { } -private[data] sealed trait IRWSTInstances1 extends IRWSTInstances2 { +private[data] sealed abstract class IRWSTInstances1 extends IRWSTInstances2 { implicit def catsDataMonadForRWST[F[_], E, L, S](implicit F0: Monad[F], L0: Monoid[L]): Monad[ReaderWriterStateT[F, E, L, S, ?]] = new RWSTMonad[F, E, L, S] { implicit def F: Monad[F] = F0 @@ -444,7 +444,7 @@ private[data] sealed trait IRWSTInstances1 extends IRWSTInstances2 { } } -private[data] sealed trait IRWSTInstances2 extends IRWSTInstances3 { +private[data] sealed abstract class IRWSTInstances2 extends IRWSTInstances3 { implicit def catsDataAlternativeForIRWST[F[_], E, L, S](implicit FM: Monad[F], FA: Alternative[F], L0: Monoid[L]): Alternative[IndexedReaderWriterStateT[F, E, L, S, S, ?]] = new RWSTAlternative[F, E, L, S] { @@ -454,7 +454,7 @@ private[data] sealed trait IRWSTInstances2 extends IRWSTInstances3 { } } -private[data] sealed trait IRWSTInstances3 { +private[data] sealed abstract class IRWSTInstances3 { implicit def catsDataSemigroupKForIRWST[F[_], E, L, SA, SB](implicit F0: Monad[F], G0: SemigroupK[F]): SemigroupK[IndexedReaderWriterStateT[F, E, L, SA, SB, ?]] = new IRWSTSemigroupK[F, E, L, SA, SB] { @@ -468,35 +468,35 @@ private[data] sealed trait IRWSTInstances3 { } } -private[data] sealed trait IRWSTFunctor[F[_], E, L, SA, SB] extends Functor[IndexedReaderWriterStateT[F, E, L, SA, SB, ?]] { +private[data] sealed abstract class IRWSTFunctor[F[_], E, L, SA, SB] extends Functor[IndexedReaderWriterStateT[F, E, L, SA, SB, ?]] { implicit def F: Functor[F] override def map[A, B](fa: IndexedReaderWriterStateT[F, E, L, SA, SB, A])(f: A => B): IndexedReaderWriterStateT[F, E, L, SA, SB, B] = fa.map(f) } -private[data] sealed trait IRWSTContravariant[F[_], E, L, SB, T] extends Contravariant[IndexedReaderWriterStateT[F, E, L, ?, SB, T]] { +private[data] sealed abstract class IRWSTContravariant[F[_], E, L, SB, T] extends Contravariant[IndexedReaderWriterStateT[F, E, L, ?, SB, T]] { implicit def F: Functor[F] override def contramap[A, B](fa: IndexedReaderWriterStateT[F, E, L, A, SB, T])(f: B => A): IndexedReaderWriterStateT[F, E, L, B, SB, T] = fa.contramap(f) } -private[data] sealed trait IRWSTProfunctor[F[_], E, L, T] extends Profunctor[IndexedReaderWriterStateT[F, E, L, ?, ?, T]] { +private[data] sealed abstract class IRWSTProfunctor[F[_], E, L, T] extends Profunctor[IndexedReaderWriterStateT[F, E, L, ?, ?, T]] { implicit def F: Functor[F] override def dimap[A, B, C, D](fab: IndexedReaderWriterStateT[F, E, L, A, B, T])(f: C => A)(g: B => D): IndexedReaderWriterStateT[F, E, L, C, D, T] = fab.dimap(f)(g) } -private[data] sealed trait IRWSTBifunctor[F[_], E, L, SA] extends Bifunctor[IndexedReaderWriterStateT[F, E, L, SA, ?, ?]] { +private[data] sealed abstract class IRWSTBifunctor[F[_], E, L, SA] extends Bifunctor[IndexedReaderWriterStateT[F, E, L, SA, ?, ?]] { implicit def F: Functor[F] override def bimap[A, B, C, D](fab: IndexedReaderWriterStateT[F, E, L, SA, A, B])(f: A => C, g: B => D): IndexedReaderWriterStateT[F, E, L, SA, C, D] = fab.bimap(f, g) } -private[data] sealed trait RWSTMonad[F[_], E, L, S] extends Monad[ReaderWriterStateT[F, E, L, S, ?]] with IRWSTFunctor[F, E, L, S, S] { +private[data] sealed abstract class RWSTMonad[F[_], E, L, S] extends IRWSTFunctor[F, E, L, S, S] with Monad[ReaderWriterStateT[F, E, L, S, ?]] { implicit def F: Monad[F] implicit def L: Monoid[L] @@ -516,7 +516,7 @@ private[data] sealed trait RWSTMonad[F[_], E, L, S] extends Monad[ReaderWriterSt } } -private[data] sealed trait IRWSTSemigroupK[F[_], E, L, SA, SB] extends SemigroupK[IndexedReaderWriterStateT[F, E, L, SA, SB, ?]] { +private[data] sealed abstract class IRWSTSemigroupK[F[_], E, L, SA, SB] extends SemigroupK[IndexedReaderWriterStateT[F, E, L, SA, SB, ?]] { implicit def F: Monad[F] implicit def G: SemigroupK[F] @@ -527,14 +527,19 @@ private[data] sealed trait IRWSTSemigroupK[F[_], E, L, SA, SB] extends Semigroup } } -private[data] sealed trait RWSTAlternative[F[_], E, L, S] - extends Alternative[ReaderWriterStateT[F, E, L, S, ?]] with IRWSTFunctor[F, E, L, S, S] - with IRWSTSemigroupK[F, E, L, S, S] { +private[data] sealed abstract class RWSTAlternative[F[_], E, L, S] + extends IRWSTFunctor[F, E, L, S, S] with Alternative[ReaderWriterStateT[F, E, L, S, ?]] { implicit def F: Monad[F] - override def G: Alternative[F] + def G: Alternative[F] implicit def L: Monoid[L] + def combineK[A](x: ReaderWriterStateT[F, E, L, S, A], + y: ReaderWriterStateT[F, E, L, S, A]): ReaderWriterStateT[F, E, L, S, A] = + ReaderWriterStateT { (e, sa) => + G.combineK(x.run(e, sa), y.run(e, sa)) + } + def empty[A]: ReaderWriterStateT[F, E, L, S, A] = ReaderWriterStateT.lift(G.empty[A]) def pure[A](a: A): ReaderWriterStateT[F, E, L, S, A] = ReaderWriterStateT.pure[F, E, L, S, A](a) @@ -544,7 +549,7 @@ private[data] sealed trait RWSTAlternative[F[_], E, L, S] } -private[data] sealed trait RWSTMonadError[F[_], E, L, S, R] +private[data] sealed abstract class RWSTMonadError[F[_], E, L, S, R] extends RWSTMonad[F, E, L, S] with MonadError[ReaderWriterStateT[F, E, L, S, ?], R] { implicit def F: MonadError[F, R] @@ -556,4 +561,3 @@ private[data] sealed trait RWSTMonadError[F[_], E, L, S, R] F.handleErrorWith(fa.run(e, s))(r => f(r).run(e, s)) } } - From 201ea74d29648756ebe139839a8956b0293bb83d Mon Sep 17 00:00:00 2001 From: Itamar Ravid Date: Sun, 10 Sep 2017 10:47:58 +0300 Subject: [PATCH 5/9] Add Strong and Arrow instances for IRWST --- .../scala/cats/data/ReaderWriterStateT.scala | 52 ++++++++++++++++++- .../cats/tests/ReaderWriterStateTTests.scala | 13 ++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/data/ReaderWriterStateT.scala b/core/src/main/scala/cats/data/ReaderWriterStateT.scala index 8dcd5a60fd..78e5c3e8eb 100644 --- a/core/src/main/scala/cats/data/ReaderWriterStateT.scala +++ b/core/src/main/scala/cats/data/ReaderWriterStateT.scala @@ -1,7 +1,8 @@ package cats package data -import cats.functor.{ Bifunctor, Contravariant, Profunctor } +import cats.functor.{ Bifunctor, Contravariant, Profunctor, Strong } +import cats.arrow.Arrow import cats.syntax.either._ /** @@ -442,6 +443,11 @@ private[data] sealed abstract class IRWSTInstances1 extends IRWSTInstances2 { implicit def F: Monad[F] = F0 implicit def L: Monoid[L] = L0 } + + implicit def catsDataStrongForIRWST[F[_], E, L, T](implicit F0: Monad[F]): Strong[IndexedReaderWriterStateT[F, E, L, ?, ?, T]] = + new IRWSTStrong[F, E, L, T] { + implicit def F: Monad[F] = F0 + } } private[data] sealed abstract class IRWSTInstances2 extends IRWSTInstances3 { @@ -452,6 +458,13 @@ private[data] sealed abstract class IRWSTInstances2 extends IRWSTInstances3 { implicit def F: Monad[F] = FM implicit def L: Monoid[L] = L0 } + + implicit def catsDataArrowForIRWST[F[_], E, L, T](implicit F0: Monad[F], L0: Monoid[L], T0: Monoid[T]): Arrow[IndexedReaderWriterStateT[F, E, L, ?, ?, T]] = + new IRWSTArrow[F, E, L, T] { + implicit def F: Monad[F] = F0 + implicit def L: Monoid[L] = L0 + implicit def T: Monoid[T] = T0 + } } private[data] sealed abstract class IRWSTInstances3 { @@ -489,6 +502,43 @@ private[data] sealed abstract class IRWSTProfunctor[F[_], E, L, T] extends Profu fab.dimap(f)(g) } +private[data] sealed abstract class IRWSTStrong[F[_], E, L, T] extends IRWSTProfunctor[F, E, L, T] with Strong[IndexedReaderWriterStateT[F, E, L, ?, ?, T]] { + implicit def F: Monad[F] + + def first[A, B, C](fa: IndexedReaderWriterStateT[F, E, L, A, B, T]): IndexedReaderWriterStateT[F, E, L, (A, C), (B, C), T] = + IndexedReaderWriterStateT { case (e, (a, c)) => + F.map(fa.run(e, a)) { case (l, b, t) => + (l, (b, c), t) + } + } + + def second[A, B, C](fa: IndexedReaderWriterStateT[F, E, L, A, B, T]): IndexedReaderWriterStateT[F, E, L, (C, A), (C, B), T] = + first(fa).dimap((_: (C, A)).swap)(_.swap) +} + +private[data] sealed abstract class IRWSTArrow[F[_], E, L, T] extends IRWSTStrong[F, E, L, T] with Arrow[IndexedReaderWriterStateT[F, E, L, ?, ?, T]] { + implicit def F: Monad[F] + implicit def T: Monoid[T] + implicit def L: Monoid[L] + + def lift[A, B](f: A => B): IndexedReaderWriterStateT[F, E, L, A, B, T] = + IndexedReaderWriterStateT { (e, a) => + F.pure((L.empty, f(a), T.empty)) + } + + def id[A]: IndexedReaderWriterStateT[F, E, L, A, A, T] = + IndexedReaderWriterStateT.pure(T.empty) + + def compose[A, B, C](f: IndexedReaderWriterStateT[F, E, L, B, C, T], g: IndexedReaderWriterStateT[F, E, L, A, B, T]): IndexedReaderWriterStateT[F, E, L, A, C, T] = + IndexedReaderWriterStateT { (e, a) => + F.flatMap(g.run(e, a)) { case (la, b, ta) => + F.map(f.run(e, b)) { case (lb, c, tb) => + (L.combine(la, lb), c, T.combine(ta, tb)) + } + } + } +} + private[data] sealed abstract class IRWSTBifunctor[F[_], E, L, SA] extends Bifunctor[IndexedReaderWriterStateT[F, E, L, SA, ?, ?]] { implicit def F: Functor[F] diff --git a/tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala b/tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala index 403408dd2b..6dae6d8a92 100644 --- a/tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala +++ b/tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala @@ -1,8 +1,9 @@ package cats package tests +import cats.arrow.Arrow import cats.data.{ IRWST, IndexedReaderWriterStateT, ReaderWriterStateT, ReaderWriterState, EitherT } -import cats.functor.{ Contravariant, Bifunctor, Profunctor } +import cats.functor.{ Contravariant, Bifunctor, Profunctor, Strong } import cats.laws.discipline._ import cats.laws.discipline.eq._ import cats.laws.discipline.arbitrary._ @@ -322,6 +323,16 @@ class ReaderWriterStateTTests extends CatsSuite { checkAll("Profunctor[IndexedReaderWriterStateT[ListWrapper, String, String, ?, ?, Int]]", SerializableTests.serializable(Profunctor[IndexedReaderWriterStateT[ListWrapper, String, String, ?, ?, Int]])) + checkAll("IndexedReaderWriterStateT[ListWrapper, String, String, Int, String, Int]", + StrongTests[IndexedReaderWriterStateT[ListWrapper, String, String, ?, ?, Int]].strong[Int, Int, Int, String, String, String]) + checkAll("Strong[IndexedReaderWriterStateT[ListWrapper, String, String, ?, ?, Int]]", + SerializableTests.serializable(Strong[IndexedReaderWriterStateT[ListWrapper, String, String, ?, ?, Int]])) + + checkAll("IndexedReaderWriterStateT[ListWrapper, String, String, Int, String, Int]", + ArrowTests[IndexedReaderWriterStateT[ListWrapper, String, String, ?, ?, Int]].arrow[Int, Int, Int, String, String, String]) + checkAll("Arrow[IndexedReaderWriterStateT[ListWrapper, String, String, ?, ?, Int]]", + SerializableTests.serializable(Arrow[IndexedReaderWriterStateT[ListWrapper, String, String, ?, ?, Int]])) + checkAll("IndexedReaderWriterStateT[ListWrapper, String, String, Int, Int, String]", BifunctorTests[IndexedReaderWriterStateT[ListWrapper, String, String, Int, ?, ?]].bifunctor[Int, Int, Int, String, String, String]) checkAll("Bifunctor[IndexedReaderWriterStateT[ListWrapper, String, String, Int, ?, ?]]", From 1a66b783a6bc3c4c027156b1696255fdd8294ec8 Mon Sep 17 00:00:00 2001 From: Itamar Ravid Date: Mon, 11 Sep 2017 08:50:02 +0300 Subject: [PATCH 6/9] Remove arrow instance --- .../scala/cats/data/ReaderWriterStateT.scala | 31 ------------------- .../cats/tests/ReaderWriterStateTTests.scala | 6 ---- 2 files changed, 37 deletions(-) diff --git a/core/src/main/scala/cats/data/ReaderWriterStateT.scala b/core/src/main/scala/cats/data/ReaderWriterStateT.scala index 78e5c3e8eb..0c8052f425 100644 --- a/core/src/main/scala/cats/data/ReaderWriterStateT.scala +++ b/core/src/main/scala/cats/data/ReaderWriterStateT.scala @@ -2,7 +2,6 @@ package cats package data import cats.functor.{ Bifunctor, Contravariant, Profunctor, Strong } -import cats.arrow.Arrow import cats.syntax.either._ /** @@ -458,13 +457,6 @@ private[data] sealed abstract class IRWSTInstances2 extends IRWSTInstances3 { implicit def F: Monad[F] = FM implicit def L: Monoid[L] = L0 } - - implicit def catsDataArrowForIRWST[F[_], E, L, T](implicit F0: Monad[F], L0: Monoid[L], T0: Monoid[T]): Arrow[IndexedReaderWriterStateT[F, E, L, ?, ?, T]] = - new IRWSTArrow[F, E, L, T] { - implicit def F: Monad[F] = F0 - implicit def L: Monoid[L] = L0 - implicit def T: Monoid[T] = T0 - } } private[data] sealed abstract class IRWSTInstances3 { @@ -516,29 +508,6 @@ private[data] sealed abstract class IRWSTStrong[F[_], E, L, T] extends IRWSTProf first(fa).dimap((_: (C, A)).swap)(_.swap) } -private[data] sealed abstract class IRWSTArrow[F[_], E, L, T] extends IRWSTStrong[F, E, L, T] with Arrow[IndexedReaderWriterStateT[F, E, L, ?, ?, T]] { - implicit def F: Monad[F] - implicit def T: Monoid[T] - implicit def L: Monoid[L] - - def lift[A, B](f: A => B): IndexedReaderWriterStateT[F, E, L, A, B, T] = - IndexedReaderWriterStateT { (e, a) => - F.pure((L.empty, f(a), T.empty)) - } - - def id[A]: IndexedReaderWriterStateT[F, E, L, A, A, T] = - IndexedReaderWriterStateT.pure(T.empty) - - def compose[A, B, C](f: IndexedReaderWriterStateT[F, E, L, B, C, T], g: IndexedReaderWriterStateT[F, E, L, A, B, T]): IndexedReaderWriterStateT[F, E, L, A, C, T] = - IndexedReaderWriterStateT { (e, a) => - F.flatMap(g.run(e, a)) { case (la, b, ta) => - F.map(f.run(e, b)) { case (lb, c, tb) => - (L.combine(la, lb), c, T.combine(ta, tb)) - } - } - } -} - private[data] sealed abstract class IRWSTBifunctor[F[_], E, L, SA] extends Bifunctor[IndexedReaderWriterStateT[F, E, L, SA, ?, ?]] { implicit def F: Functor[F] diff --git a/tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala b/tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala index 6dae6d8a92..cfafd207a0 100644 --- a/tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala +++ b/tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala @@ -1,7 +1,6 @@ package cats package tests -import cats.arrow.Arrow import cats.data.{ IRWST, IndexedReaderWriterStateT, ReaderWriterStateT, ReaderWriterState, EitherT } import cats.functor.{ Contravariant, Bifunctor, Profunctor, Strong } import cats.laws.discipline._ @@ -328,11 +327,6 @@ class ReaderWriterStateTTests extends CatsSuite { checkAll("Strong[IndexedReaderWriterStateT[ListWrapper, String, String, ?, ?, Int]]", SerializableTests.serializable(Strong[IndexedReaderWriterStateT[ListWrapper, String, String, ?, ?, Int]])) - checkAll("IndexedReaderWriterStateT[ListWrapper, String, String, Int, String, Int]", - ArrowTests[IndexedReaderWriterStateT[ListWrapper, String, String, ?, ?, Int]].arrow[Int, Int, Int, String, String, String]) - checkAll("Arrow[IndexedReaderWriterStateT[ListWrapper, String, String, ?, ?, Int]]", - SerializableTests.serializable(Arrow[IndexedReaderWriterStateT[ListWrapper, String, String, ?, ?, Int]])) - checkAll("IndexedReaderWriterStateT[ListWrapper, String, String, Int, Int, String]", BifunctorTests[IndexedReaderWriterStateT[ListWrapper, String, String, Int, ?, ?]].bifunctor[Int, Int, Int, String, String, String]) checkAll("Bifunctor[IndexedReaderWriterStateT[ListWrapper, String, String, Int, ?, ?]]", From 99e6a95504ff1ccedaab9fc4b77c37f0366d398f Mon Sep 17 00:00:00 2001 From: Itamar Ravid Date: Tue, 12 Sep 2017 07:38:08 +0300 Subject: [PATCH 7/9] Rename files --- .../{ReaderWriterStateT.scala => IndexedReaderWriterStateT.scala} | 0 ...iterStateTTests.scala => IndexedReaderWriterStateTTests.scala} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename core/src/main/scala/cats/data/{ReaderWriterStateT.scala => IndexedReaderWriterStateT.scala} (100%) rename tests/src/test/scala/cats/tests/{ReaderWriterStateTTests.scala => IndexedReaderWriterStateTTests.scala} (100%) diff --git a/core/src/main/scala/cats/data/ReaderWriterStateT.scala b/core/src/main/scala/cats/data/IndexedReaderWriterStateT.scala similarity index 100% rename from core/src/main/scala/cats/data/ReaderWriterStateT.scala rename to core/src/main/scala/cats/data/IndexedReaderWriterStateT.scala diff --git a/tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala b/tests/src/test/scala/cats/tests/IndexedReaderWriterStateTTests.scala similarity index 100% rename from tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala rename to tests/src/test/scala/cats/tests/IndexedReaderWriterStateTTests.scala From 893c4b6de8d9f204f7f742e1b327c3c9c450dc29 Mon Sep 17 00:00:00 2001 From: Itamar Ravid Date: Tue, 12 Sep 2017 07:39:11 +0300 Subject: [PATCH 8/9] Revert scaladoc tweak --- core/src/main/scala/cats/data/IndexedReaderWriterStateT.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/data/IndexedReaderWriterStateT.scala b/core/src/main/scala/cats/data/IndexedReaderWriterStateT.scala index 0c8052f425..99206a09e9 100644 --- a/core/src/main/scala/cats/data/IndexedReaderWriterStateT.scala +++ b/core/src/main/scala/cats/data/IndexedReaderWriterStateT.scala @@ -9,7 +9,7 @@ import cats.syntax.either._ * with an initial environment `E`, an accumulated log `L` and a result `A`. * * In other words, it is a pre-baked stack of `[[ReaderT]][F, E, A]`, `[[WriterT]][F, L, A]` - * and `IndexedStateT[F, SA, SB, A]`. + * and `[[IndexedStateT]][F, SA, SB, A]`. */ final class IndexedReaderWriterStateT[F[_], E, L, SA, SB, A](val runF: F[(E, SA) => F[(L, SB, A)]]) extends Serializable { From 0f92292834269df6cc9628b386bf565443bec26a Mon Sep 17 00:00:00 2001 From: Itamar Ravid Date: Tue, 12 Sep 2017 08:22:25 +0300 Subject: [PATCH 9/9] Improve coverage --- core/src/main/scala/cats/data/IndexedReaderWriterStateT.scala | 3 +++ .../test/scala/cats/tests/IndexedReaderWriterStateTTests.scala | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/data/IndexedReaderWriterStateT.scala b/core/src/main/scala/cats/data/IndexedReaderWriterStateT.scala index 99206a09e9..0a5c384678 100644 --- a/core/src/main/scala/cats/data/IndexedReaderWriterStateT.scala +++ b/core/src/main/scala/cats/data/IndexedReaderWriterStateT.scala @@ -33,6 +33,9 @@ final class IndexedReaderWriterStateT[F[_], E, L, SA, SB, A](val runF: F[(E, SA) * scala> type Log = List[String] * scala> val xLocal: IndexedReaderWriterStateT[Option, Env, Log, Int, Int, Int] = IndexedReaderWriterStateT.get * scala> val xGlobal: IndexedReaderWriterStateT[Option, GlobalEnv, Log, Int, Int, Int] = xLocal.local(_._2) + * scala> val globalEnv: GlobalEnv = (5, "env") + * scala> xGlobal.run(globalEnv, 5) + * res0: Option[(List[String], Int, Int)] = Some((List(),5,5)) * }}} */ def local[EE](f: EE => E)(implicit F: Functor[F]): IndexedReaderWriterStateT[F, EE, L, SA, SB, A] = diff --git a/tests/src/test/scala/cats/tests/IndexedReaderWriterStateTTests.scala b/tests/src/test/scala/cats/tests/IndexedReaderWriterStateTTests.scala index cfafd207a0..e5bb928007 100644 --- a/tests/src/test/scala/cats/tests/IndexedReaderWriterStateTTests.scala +++ b/tests/src/test/scala/cats/tests/IndexedReaderWriterStateTTests.scala @@ -338,7 +338,7 @@ class ReaderWriterStateTTests extends CatsSuite { val SA = IRWST.catsDataAlternativeForIRWST[ListWrapper, String, String, Int](ListWrapper.monad, ListWrapper.alternative, Monoid[String]) - checkAll("IndexedReaderWriterStateT[ListWrapper, String, String, Int, Int, Int]", AlternativeTests[IRWST[ListWrapper, String, String, Int, Int, ?]](SA).monoidK[Int]) + checkAll("IndexedReaderWriterStateT[ListWrapper, String, String, Int, Int, Int]", AlternativeTests[IRWST[ListWrapper, String, String, Int, Int, ?]](SA).alternative[Int, Int, Int]) checkAll("Alternative[IndexedReaderWriterStateT[ListWrapper, String, String, Int, Int, ?]]", SerializableTests.serializable(SA)) }