Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert StateT to IndexedStateT #1775

Merged
merged 16 commits into from
Sep 11, 2017
Merged
229 changes: 151 additions & 78 deletions core/src/main/scala/cats/data/StateT.scala
Original file line number Diff line number Diff line change
@@ -1,75 +1,90 @@
package cats
package data

import cats.functor.{ Contravariant, Profunctor }
import cats.syntax.either._

/**
* `StateT[F, S, A]` is similar to `Kleisli[F, S, A]` in that it takes an `S`
* argument and produces an `A` value wrapped in `F`. However, it also produces
* an `S` value representing the updated state (which is wrapped in the `F`
* context along with the `A` value.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move the old StateT documentation to the StateT type alias in package.scala?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

*
* `IndexedStateT[F, SA, SB, A]` is a stateful computation in a context `F` yielding
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you comment about the Indexed name here? I don't know the context, though I can understand the rest of the comments.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @johnynek. I refined the scaladoc here. See if that makes it more descriptive.

* a value of type `A`. Its state transitions from a value of type `SA` to a value
* of type `SB`.
*
* Given `IndexedStateT[F, S, S, A]`, this yields the plain `StateT[F, S, A]`.
*
* Note that `IndexedStateT[F, SA, SB, A]` is not a monad, but an indexed monad.
*/
final class StateT[F[_], S, A](val runF: F[S => F[(S, A)]]) extends Serializable {
final class IndexedStateT[F[_], SA, SB, A](val runF: F[SA => F[(SB, A)]]) extends Serializable {

def flatMap[B](fas: A => StateT[F, S, B])(implicit F: FlatMap[F]): StateT[F, S, B] =
StateT.applyF(F.map(runF) { sfsa =>
sfsa.andThen { fsa =>
F.flatMap(fsa) { case (s, a) =>
fas(a).run(s)
def flatMap[B, SC](fas: A => IndexedStateT[F, SB, SC, B])(implicit F: FlatMap[F]): IndexedStateT[F, SA, SC, B] =
IndexedStateT.applyF(F.map(runF) { safsba =>
safsba.andThen { fsba =>
F.flatMap(fsba) { case (sb, a) =>
fas(a).run(sb)
}
}
})

def flatMapF[B](faf: A => F[B])(implicit F: FlatMap[F]): StateT[F, S, B] =
StateT.applyF(F.map(runF) { sfsa =>
def flatMapF[B](faf: A => F[B])(implicit F: FlatMap[F]): IndexedStateT[F, SA, SB, B] =
IndexedStateT.applyF(F.map(runF) { sfsa =>
sfsa.andThen { fsa =>
F.flatMap(fsa) { case (s, a) => F.map(faf(a))((s, _)) }
}
})

def map[B](f: A => B)(implicit F: Functor[F]): StateT[F, S, B] =
def map[B](f: A => B)(implicit F: Functor[F]): IndexedStateT[F, SA, SB, B] =
transform { case (s, a) => (s, f(a)) }

def contramap[S0](f: S0 => SA)(implicit F: Monad[F]): IndexedStateT[F, S0, SB, A] =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't this only need Applicative[F]?

(pure(f), runF).map2(_.andThen(_)) I think does it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! That's awesome, thank you :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Downgraded dimap too

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the noise. Turns out it's just Functor that's needed for both.

IndexedStateT.apply { s0 =>
F.flatMap(runF) { safsba =>
safsba(f(s0))
}
}

def dimap[S0, S1](f: S0 => SA)(g: SB => S1)(implicit F: Monad[F]): IndexedStateT[F, S0, S1, A] =
contramap(f).modify(g)

/**
* Run with the provided initial state value
*/
def run(initial: S)(implicit F: FlatMap[F]): F[(S, A)] =
def run(initial: SA)(implicit F: FlatMap[F]): F[(SB, A)] =
F.flatMap(runF)(f => f(initial))

/**
* Run with the provided initial state value and return the final state
* (discarding the final value).
*/
def runS(s: S)(implicit F: FlatMap[F]): F[S] = F.map(run(s))(_._1)
def runS(s: SA)(implicit F: FlatMap[F]): F[SB] = F.map(run(s))(_._1)

/**
* Run with the provided initial state value and return the final value
* (discarding the final state).
*/
def runA(s: S)(implicit F: FlatMap[F]): F[A] = F.map(run(s))(_._2)
def runA(s: SA)(implicit F: FlatMap[F]): F[A] = F.map(run(s))(_._2)

/**
* Run with `S`'s empty monoid value as the initial state.
*/
def runEmpty(implicit S: Monoid[S], F: FlatMap[F]): F[(S, A)] = run(S.empty)
def runEmpty(implicit S: Monoid[SA], F: FlatMap[F]): F[(SB, A)] = run(S.empty)

/**
* Run with `S`'s empty monoid value as the initial state and return the final
* state (discarding the final value).
*/
def runEmptyS(implicit S: Monoid[S], F: FlatMap[F]): F[S] = runS(S.empty)
def runEmptyS(implicit S: Monoid[SA], F: FlatMap[F]): F[SB] = runS(S.empty)

/**
* Run with `S`'s empty monoid value as the initial state and return the final
* value (discarding the final state).
*/
def runEmptyA(implicit S: Monoid[S], F: FlatMap[F]): F[A] = runA(S.empty)
def runEmptyA(implicit S: Monoid[SA], F: FlatMap[F]): F[A] = runA(S.empty)

/**
* Like [[map]], but also allows the state (`S`) value to be modified.
*/
def transform[B](f: (S, A) => (S, B))(implicit F: Functor[F]): StateT[F, S, B] =
StateT.applyF(
def transform[B, SC](f: (SB, A) => (SC, B))(implicit F: Functor[F]): IndexedStateT[F, SA, SC, B] =
IndexedStateT.applyF(
F.map(runF) { sfsa =>
sfsa.andThen { fsa =>
F.map(fsa) { case (s, a) => f(s, a) }
Expand All @@ -79,8 +94,8 @@ final class StateT[F[_], S, A](val runF: F[S => F[(S, A)]]) extends Serializable
/**
* Like [[transform]], but allows the context to change from `F` to `G`.
*/
def transformF[G[_], B](f: F[(S, A)] => G[(S, B)])(implicit F: FlatMap[F], G: Applicative[G]): StateT[G, S, B] =
StateT(s => f(run(s)))
def transformF[G[_], B, SC](f: F[(SB, A)] => G[(SC, B)])(implicit F: FlatMap[F], G: Applicative[G]): IndexedStateT[G, SA, SC, B] =
IndexedStateT(s => f(run(s)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not covered, maybe a doctest?


/**
* Transform the state used.
Expand All @@ -100,98 +115,139 @@ final class StateT[F[_], S, A](val runF: F[S => F[(S, A)]]) extends Serializable
* res1: Option[(GlobalEnv, Double)] = Some(((6,hello),5.0))
* }}}
*/
def transformS[R](f: R => S, g: (R, S) => R)(implicit F: Functor[F]): StateT[F, R, A] =
def transformS[R](f: R => SA, g: (R, SB) => R)(implicit F: Functor[F]): IndexedStateT[F, R, R, A] =
StateT.applyF(F.map(runF) { sfsa =>
{ r: R =>
val s = f(r)
val fsa = sfsa(s)
F.map(fsa) { case (s, a) => (g(r, s), a) }
val sa = f(r)
val fsba = sfsa(sa)
F.map(fsba) { case (sb, a) => (g(r, sb), a) }
}
})

/**
* Modify the state (`S`) component.
*/
def modify(f: S => S)(implicit F: Functor[F]): StateT[F, S, A] =
def modify[SC](f: SB => SC)(implicit F: Functor[F]): IndexedStateT[F, SA, SC, A] =
transform((s, a) => (f(s), a))

/**
* Inspect a value from the input state, without modifying the state.
*/
def inspect[B](f: S => B)(implicit F: Functor[F]): StateT[F, S, B] =
def inspect[B](f: SB => B)(implicit F: Functor[F]): IndexedStateT[F, SA, SB, B] =
transform((s, _) => (s, f(s)))

/**
* Get the input state, without modifying the state.
*/
def get(implicit F: Functor[F]): StateT[F, S, S] =
def get(implicit F: Functor[F]): IndexedStateT[F, SA, SB, SB] =
inspect(identity)
}

object StateT extends StateTInstances {
object IndexedStateT extends IndexedStateTInstances {
def apply[F[_], SA, SB, A](f: SA => F[(SB, A)])(implicit F: Applicative[F]): IndexedStateT[F, SA, SB, A] =
new IndexedStateT(F.pure(f))

def applyF[F[_], SA, SB, A](runF: F[SA => F[(SB, A)]]): IndexedStateT[F, SA, SB, A] =
new IndexedStateT(runF)

def pure[F[_], S, A](a: A)(implicit F: Applicative[F]): IndexedStateT[F, S, S, A] =
IndexedStateT(s => F.pure((s, a)))

def lift[F[_], S, A](fa: F[A])(implicit F: Applicative[F]): IndexedStateT[F, S, S, A] =
IndexedStateT(s => F.map(fa)(a => (s, a)))

def inspect[F[_], S, A](f: S => A)(implicit F: Applicative[F]): IndexedStateT[F, S, S, A] =
IndexedStateT(s => F.pure((s, f(s))))

def inspectF[F[_], S, A](f: S => F[A])(implicit F: Applicative[F]): IndexedStateT[F, S, S, A] =
IndexedStateT(s => F.map(f(s))(a => (s, a)))

def modify[F[_], SA, SB](f: SA => SB)(implicit F: Applicative[F]): IndexedStateT[F, SA, SB, Unit] =
IndexedStateT(sa => F.pure((f(sa), ())))

def modifyF[F[_], SA, SB](f: SA => F[SB])(implicit F: Applicative[F]): IndexedStateT[F, SA, SB, Unit] =
IndexedStateT(s => F.map(f(s))(s => (s, ())))

def get[F[_], S](implicit F: Applicative[F]): IndexedStateT[F, S, S, S] =
IndexedStateT(s => F.pure((s, s)))

def set[F[_], SA, SB](sb: SB)(implicit F: Applicative[F]): IndexedStateT[F, SA, SB, Unit] =
IndexedStateT(_ => F.pure((sb, ())))

def setF[F[_], SA, SB](fsb: F[SB])(implicit F: Applicative[F]): IndexedStateT[F, SA, SB, Unit] =
IndexedStateT(_ => F.map(fsb)(s => (s, ())))
}

private[data] abstract class StateTFunctions {
def apply[F[_], S, A](f: S => F[(S, A)])(implicit F: Applicative[F]): StateT[F, S, A] =
new StateT(F.pure(f))
IndexedStateT(f)

def applyF[F[_], S, A](runF: F[S => F[(S, A)]]): StateT[F, S, A] =
new StateT(runF)
IndexedStateT.applyF(runF)

def pure[F[_], S, A](a: A)(implicit F: Applicative[F]): StateT[F, S, A] =
StateT(s => F.pure((s, a)))
apply(s => F.pure((s, a)))

def lift[F[_], S, A](fa: F[A])(implicit F: Applicative[F]): StateT[F, S, A] =
StateT(s => F.map(fa)(a => (s, a)))
apply(s => F.map(fa)(a => (s, a)))

def inspect[F[_], S, A](f: S => A)(implicit F: Applicative[F]): StateT[F, S, A] =
StateT(s => F.pure((s, f(s))))
apply(s => F.pure((s, f(s))))

def inspectF[F[_], S, A](f: S => F[A])(implicit F: Applicative[F]): StateT[F, S, A] =
StateT(s => F.map(f(s))(a => (s, a)))
apply(s => F.map(f(s))(a => (s, a)))

def modify[F[_], S](f: S => S)(implicit F: Applicative[F]): StateT[F, S, Unit] =
StateT(s => F.pure((f(s), ())))
apply(sa => F.pure((f(sa), ())))

def modifyF[F[_], S](f: S => F[S])(implicit F: Applicative[F]): StateT[F, S, Unit] =
StateT(s => F.map(f(s))(s => (s, ())))
apply(s => F.map(f(s))(s => (s, ())))

def get[F[_], S](implicit F: Applicative[F]): StateT[F, S, S] =
StateT(s => F.pure((s, s)))
apply(s => F.pure((s, s)))

def set[F[_], S](s: S)(implicit F: Applicative[F]): StateT[F, S, Unit] =
StateT(_ => F.pure((s, ())))
apply(_ => F.pure((s, ())))

def setF[F[_], S](fs: F[S])(implicit F: Applicative[F]): StateT[F, S, Unit] =
StateT(_ => F.map(fs)(s => (s, ())))
apply(_ => F.map(fs)(s => (s, ())))
}

private[data] sealed trait StateTInstances extends StateTInstances1 {
implicit def catsDataAlternativeForStateT[F[_], S](implicit FM: Monad[F], FA: Alternative[F]): Alternative[StateT[F, S, ?]] =
new StateTAlternative[F, S] { implicit def F = FM; implicit def G = FA }
private[data] sealed trait IndexedStateTInstances extends IndexedStateTInstances1 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

per #1879 do you mind change all the instance traits here into abstract class? I am creating a PR to change other classes, but don't want to touch this one to avoid conflict.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

implicit def catsDataAlternativeForIndexedStateT[F[_], S](implicit FM: Monad[F], FA: Alternative[F]): Alternative[StateT[F, S, ?]] =
Copy link
Contributor

@kailuowang kailuowang Aug 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder what if you make this instance an Alternative[StateT[F, S, ?]] with Monad[StateT[F, S, ?]] and let IndexedStateTAlternative inherit IndexedStateTMonad. Since without the ap, IndexedStateTAlternative can't be used without mixin with IndexedStateTMonad
Do you still need to override pure?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will try :-) would that approach look cleaner? Personally I have no preference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely cleaner

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make the return type Alternative[StateT[F, S, ?]] with Monad[StateT[F, S, ?]] here as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @kailuowang - I actually changed Alternative to extend Monad, so there's no need for the intersection type now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I meant. Since you are in effect returning an Alternative with Monad, why hide the fact that it's a Monad? It has a lot more power than the return type suggests. I just felt a bit odd that your return type isn't the actual public type of the instance. Odd code take a bit more time for code reader to grasp, that's all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My reasoning was that this was about implicit search priorities: let the catsDataAlternativeForIndexedStateT return only an Alternative instance, and let the catsDataMonadForIndexedStateT handle the Monad instance, while hiding the fact that the Alternative instance in fact uses the Monad instance.

If you find that returning the intersection type makes more sense, I'll fix that right away :-) Just haven't seen this done anywhere else in the codebase.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have examples of returning intersection type.
/~https://github.com/typelevel/cats/blob/master/core/src/main/scala/cats/instances/list.scala#L11
IIRC, at this position instance use to be a MonadCombine which is MonadFilter with Alternative, so I don't have issues with this instance being a Monad with Alternative

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool! Thanks. Changed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for putting up with my nitpicking! I will find time to go through the whole PR tomorrow or the day after.

new IndexedStateTAlternative[F, S] { implicit def F = FM; implicit def G = FA }
}

private[data] sealed trait StateTInstances1 extends StateTInstances2 {
implicit def catsDataMonadErrorForStateT[F[_], S, E](implicit F0: MonadError[F, E]): MonadError[StateT[F, S, ?], E] =
new StateTMonadError[F, S, E] { implicit def F = F0 }
private[data] sealed trait IndexedStateTInstances1 extends IndexedStateTInstances2 {
implicit def catsDataMonadErrorForIndexedStateT[F[_], S, E](implicit F0: MonadError[F, E]): MonadError[IndexedStateT[F, S, S, ?], E] =
new IndexedStateTMonadError[F, S, E] { implicit def F = F0 }

implicit def catsDataSemigroupKForStateT[F[_], S](implicit F0: Monad[F], G0: SemigroupK[F]): SemigroupK[StateT[F, S, ?]] =
new StateTSemigroupK[F, S] { implicit def F = F0; implicit def G = G0 }
implicit def catsDataSemigroupKForIndexedStateT[F[_], SA, SB](implicit F0: Monad[F], G0: SemigroupK[F]): SemigroupK[IndexedStateT[F, SA, SB, ?]] =
new IndexedStateTSemigroupK[F, SA, SB] { implicit def F = F0; implicit def G = G0 }
}

private[data] sealed trait StateTInstances2 extends StateTInstances3 {
implicit def catsDataMonadForStateT[F[_], S](implicit F0: Monad[F]): Monad[StateT[F, S, ?]] =
new StateTMonad[F, S] { implicit def F = F0 }
private[data] sealed trait IndexedStateTInstances2 extends IndexedStateTInstances3 {
implicit def catsDataMonadForIndexedStateT[F[_], S](implicit F0: Monad[F]): Monad[IndexedStateT[F, S, S, ?]] =
new IndexedStateTMonad[F, S] { implicit def F = F0 }
}

private[data] sealed trait StateTInstances3 {
implicit def catsDataFunctorForStateT[F[_], S](implicit F0: Functor[F]): Functor[StateT[F, S, ?]] =
new StateTFunctor[F, S] { implicit def F = F0 }
private[data] sealed trait IndexedStateTInstances3 {
implicit def catsDataFunctorForIndexedStateT[F[_], SA, SB](implicit F0: Functor[F]): Functor[IndexedStateT[F, SA, SB, ?]] =
new IndexedStateTFunctor[F, SA, SB] { implicit def F = F0 }

implicit def catsDataContravariantForIndexedStateT[F[_], SB, V](implicit F0: Monad[F]): Contravariant[IndexedStateT[F, ?, SB, V]] =
new IndexedStateTContravariant[F, SB, V] { implicit def F = F0 }

implicit def catsDataProfunctorForIndexedStateT[F[_], V](implicit F0: Monad[F]): Profunctor[IndexedStateT[F, ?, ?, V]] =
new IndexedStateTProfunctor[F, V] { implicit def F = F0 }
}

// To workaround SI-7139 `object State` needs to be defined inside the package object
// together with the type alias.
private[data] abstract class StateFunctions {

def apply[S, A](f: S => (S, A)): State[S, A] =
StateT.applyF(Now((s: S) => Now(f(s))))
IndexedStateT.applyF(Now((s: S) => Now(f(s))))

/**
* Return `a` and maintain the input state.
Expand Down Expand Up @@ -219,62 +275,79 @@ private[data] abstract class StateFunctions {
def set[S](s: S): State[S, Unit] = State(_ => (s, ()))
}

private[data] sealed trait StateTFunctor[F[_], S] extends Functor[StateT[F, S, ?]] {
private[data] sealed trait IndexedStateTFunctor[F[_], SA, SB] extends Functor[IndexedStateT[F, SA, SB, ?]] {
implicit def F: Functor[F]

override def map[A, B](fa: StateT[F, S, A])(f: A => B): StateT[F, S, B] = fa.map(f)
override def map[A, B](fa: IndexedStateT[F, SA, SB, A])(f: A => B): IndexedStateT[F, SA, SB, B] =
fa.map(f)
}

private[data] sealed trait IndexedStateTContravariant[F[_], SB, V] extends Contravariant[IndexedStateT[F, ?, SB, V]] {
implicit def F: Monad[F]

override def contramap[A, B](fa: IndexedStateT[F, A, SB, V])(f: B => A): IndexedStateT[F, B, SB, V] =
fa.contramap(f)
}

private[data] sealed trait StateTMonad[F[_], S] extends Monad[StateT[F, S, ?]] with StateTFunctor[F, S] {
private[data] sealed trait IndexedStateTProfunctor[F[_], V] extends Profunctor[IndexedStateT[F, ?, ?, V]] {
implicit def F: Monad[F]

def dimap[A, B, C, D](fab: IndexedStateT[F, A, B, V])(f: C => A)(g: B => D): IndexedStateT[F, C, D, V] =
fab.dimap(f)(g)
}

private[data] sealed trait IndexedStateTMonad[F[_], S] extends Monad[IndexedStateT[F, S, S, ?]]
with IndexedStateTFunctor[F, S, S] {
implicit def F: Monad[F]

def pure[A](a: A): StateT[F, S, A] =
StateT.pure(a)
IndexedStateT.pure(a)

def flatMap[A, B](fa: StateT[F, S, A])(f: A => StateT[F, S, B]): StateT[F, S, B] =
fa.flatMap(f)

def tailRecM[A, B](a: A)(f: A => StateT[F, S, Either[A, B]]): StateT[F, S, B] =
StateT[F, S, B](s => F.tailRecM[(S, A), (S, B)]((s, a)) {
IndexedStateT[F, S, S, B](s => F.tailRecM[(S, A), (S, B)]((s, a)) {
case (s, a) => F.map(f(a).run(s)) { case (s, ab) => ab.bimap((s, _), (s, _)) }
})
}

private[data] sealed trait StateTSemigroupK[F[_], S] extends SemigroupK[StateT[F, S, ?]] {
private[data] sealed trait IndexedStateTSemigroupK[F[_], SA, SB] extends SemigroupK[IndexedStateT[F, SA, SB, ?]] {
implicit def F: Monad[F]
implicit def G: SemigroupK[F]

def combineK[A](x: StateT[F, S, A], y: StateT[F, S, A]): StateT[F, S, A] =
StateT(s => G.combineK(x.run(s), y.run(s)))
def combineK[A](x: IndexedStateT[F, SA, SB, A], y: IndexedStateT[F, SA, SB, A]): IndexedStateT[F, SA, SB, A] =
IndexedStateT(s => G.combineK(x.run(s), y.run(s)))
}

private[data] sealed trait StateTAlternative[F[_], S] extends Alternative[StateT[F, S, ?]] with StateTFunctor[F, S] {
private[data] sealed trait IndexedStateTAlternative[F[_], S] extends Alternative[IndexedStateT[F, S, S, ?]] with IndexedStateTFunctor[F, S, S] {
implicit def F: Monad[F]
def G: Alternative[F]

def combineK[A](x: StateT[F, S, A], y: StateT[F, S, A]): StateT[F, S, A] =
StateT[F, S, A](s => G.combineK(x.run(s), y.run(s)))(G)
def combineK[A](x: IndexedStateT[F, S, S, A], y: IndexedStateT[F, S, S, A]): IndexedStateT[F, S, S, A] =
IndexedStateT[F, S, S, A](s => G.combineK(x.run(s), y.run(s)))(G)

def pure[A](a: A): StateT[F, S, A] =
StateT.pure[F, S, A](a)(G)
def pure[A](a: A): IndexedStateT[F, S, S, A] =
IndexedStateT.pure[F, S, A](a)(G)

def empty[A]: StateT[F, S, A] =
StateT.lift[F, S, A](G.empty[A])(G)
def empty[A]: IndexedStateT[F, S, S, A] =
IndexedStateT.lift[F, S, A](G.empty[A])(G)

override def ap[A, B](ff: StateT[F, S, A => B])(fa: StateT[F, S, A]): StateT[F, S, B] =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am curious why remove this override?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The specific overrides for Applicative were removed in #1735, so my reasoning was that this override wasn't necessary either, and it suffices to use the implementation provided by the Monad instance

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, you made IndexedStateTAlternative require mixing with a Monad instance trait. Left some comment below.

StateT[F, S, B]((s: S) =>
override def ap[A, B](ff: IndexedStateT[F, S, S, A => B])(fa: IndexedStateT[F, S, S, A]): IndexedStateT[F, S, S, B] =
IndexedStateT[F, S, S, B]((s: S) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not covered, which is a bit surprising. Haven't go the time to investigate further.

F.flatMap(ff.run(s)) { sab =>
val (sn, f) = sab
F.map(fa.run(sn)) { case (snn, a) => (snn, f(a)) }
}
)
}

private[data] sealed trait StateTMonadError[F[_], S, E] extends StateTMonad[F, S] with MonadError[StateT[F, S, ?], E] {
private[data] sealed trait IndexedStateTMonadError[F[_], S, E] extends IndexedStateTMonad[F, S]
with MonadError[IndexedStateT[F, S, S, ?], E] {
implicit def F: MonadError[F, E]

def raiseError[A](e: E): StateT[F, S, A] = StateT.lift(F.raiseError(e))
def raiseError[A](e: E): IndexedStateT[F, S, S, A] = IndexedStateT.lift(F.raiseError(e))

def handleErrorWith[A](fa: StateT[F, S, A])(f: E => StateT[F, S, A]): StateT[F, S, A] =
StateT(s => F.handleErrorWith(fa.run(s))(e => f(e).run(s)))
def handleErrorWith[A](fa: IndexedStateT[F, S, S, A])(f: E => IndexedStateT[F, S, S, A]): IndexedStateT[F, S, S, A] =
IndexedStateT(s => F.handleErrorWith(fa.run(s))(e => f(e).run(s)))
}
Loading