All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cats.data.IndexedStateT.scala Maven / Gradle / Ivy

The newest version!
package cats
package data

import cats.arrow.{Profunctor, Strong}

import cats.syntax.either._

/**
 *
 * `IndexedStateT[F, SA, SB, A]` is a stateful computation in a context `F` yielding
 * a value of type `A`. The state transitions from a value of type `SA` to a value
 * of type `SB`.
 *
 * Note that for the `SA != SB` case, this is an indexed monad. Indexed monads
 * are monadic type constructors annotated by an additional type for effect
 * tracking purposes. In this case, the annotation tracks the initial state and
 * the resulting state.
 *
 * Given `IndexedStateT[F, S, S, A]`, this yields the `StateT[F, S, A]` monad.
 */
final class IndexedStateT[F[_], SA, SB, A](val runF: F[SA => F[(SB, A)]]) extends Serializable {

  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 =>
      AndThen(safsba).andThen { fsba =>
        F.flatMap(fsba) {
          case (sb, a) =>
            fas(a).run(sb)
        }
      }
    })

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

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

  /**
   * Modify the context `F` using transformation `f`.
   */
  def mapK[G[_]](f: F ~> G)(implicit F: Functor[F]): IndexedStateT[G, SA, SB, A] =
    IndexedStateT.applyF(f(F.map(runF)(_.andThen(fsa => f(fsa)))))

  def contramap[S0](f: S0 => SA)(implicit F: Functor[F]): IndexedStateT[F, S0, SB, A] =
    IndexedStateT.applyF {
      F.map(runF) { safsba => (s0: S0) =>
        safsba(f(s0))
      }
    }

  def bimap[SC, B](f: SB => SC, g: A => B)(implicit F: Functor[F]): IndexedStateT[F, SA, SC, B] =
    transform { (s, a) =>
      (f(s), g(a))
    }

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

  /**
   * Run with the provided initial state value
   */
  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: 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: 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[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[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[SA], F: FlatMap[F]): F[A] = runA(S.empty)

  /**
   * Like [[map]], but also allows the state (`S`) value to be modified.
   */
  def transform[B, SC](f: (SB, A) => (SC, B))(implicit F: Functor[F]): IndexedStateT[F, SA, SC, B] =
    IndexedStateT.applyF(F.map(runF) { sfsa =>
      AndThen(sfsa).andThen { fsa =>
        F.map(fsa) { case (s, a) => f(s, a) }
      }
    })

  /**
   * Like [[transform]], but allows the context to change from `F` to `G`.
   *
   * {{{
   * scala> import cats.implicits._
   * scala> type ErrorOr[A] = Either[String, A]
   * scala> val xError: IndexedStateT[ErrorOr, Int, Int, Int] = IndexedStateT.get
   * scala> val xOpt: IndexedStateT[Option, Int, Int, Int] = xError.transformF(_.toOption)
   * scala> val input = 5
   * scala> xError.run(input)
   * res0: ErrorOr[(Int, Int)] = Right((5,5))
   * scala> xOpt.run(5)
   * res1: Option[(Int, Int)] = Some((5,5))
   * }}}
   */
  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)))

  /**
   * Transform the state used.
   *
   * This is useful when you are working with many focused `StateT`s and want to pass in a
   * global state containing the various states needed for each individual `StateT`.
   *
   * {{{
   * scala> import cats.implicits._ // needed for StateT.apply
   * scala> type GlobalEnv = (Int, String)
   * scala> val x: StateT[Option, Int, Double] = StateT((x: Int) => Option((x + 1, x.toDouble)))
   * scala> val xt: StateT[Option, GlobalEnv, Double] = x.transformS[GlobalEnv](_._1, (t, i) => (i, t._2))
   * scala> val input = 5
   * scala> x.run(input)
   * res0: Option[(Int, Double)] = Some((6,5.0))
   * scala> xt.run((input, "hello"))
   * res1: Option[(GlobalEnv, Double)] = Some(((6,hello),5.0))
   * }}}
   */
  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 sa = f(r)
          val fsba = sfsa(sa)
          F.map(fsba) { case (sb, a) => (g(r, sb), a) }
        }
    })

  /**
   * Modify the state (`S`) component.
   */
  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: 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]): IndexedStateT[F, SA, SB, SB] =
    inspect(identity)
}

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

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

  /**
   * Same as [[liftF]], but expressed as a FunctionK for use with mapK
   * {{{
   * scala> import cats._, data._, implicits._
   * scala> val a: OptionT[Eval, Int] = 1.pure[OptionT[Eval, *]]
   * scala> val b: OptionT[StateT[Eval, String, *], Int] = a.mapK(StateT.liftK)
   * scala> b.value.runEmpty.value
   * res0: (String, Option[Int]) = ("",Some(1))
   * }}}
   */
  def liftK[F[_], S](implicit F: Applicative[F]): F ~> IndexedStateT[F, S, S, *] =
    λ[F ~> IndexedStateT[F, S, S, *]](IndexedStateT.liftF(_))

  @deprecated("Use liftF instead", "1.0.0-RC2")
  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 get[F[_], S](implicit F: Applicative[F]): IndexedStateT[F, S, S, S] =
    IndexedStateT(s => F.pure((s, s)))
}

object IndexedStateT extends IndexedStateTInstances with CommonStateTConstructors0 {
  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 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 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] trait CommonStateTConstructors0 extends CommonStateTConstructors {
  def empty[F[_], S, A](implicit A: Monoid[A], F: Applicative[F]): IndexedStateT[F, S, S, A] =
    pure(A.empty)
}

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

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

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

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

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

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

sealed abstract private[data] class IndexedStateTInstances extends IndexedStateTInstances1 {
  implicit def catsDataAlternativeForIndexedStateT[F[_], S](
    implicit FM: Monad[F],
    FA: Alternative[F]
  ): Alternative[IndexedStateT[F, S, S, *]] with Monad[IndexedStateT[F, S, S, *]] =
    new IndexedStateTAlternative[F, S] { implicit def F = FM; implicit def G = FA }

  implicit def catsDataDeferForIndexedStateT[F[_], SA, SB](implicit F: Defer[F]): Defer[IndexedStateT[F, SA, SB, *]] =
    new Defer[IndexedStateT[F, SA, SB, *]] {
      def defer[A](fa: => IndexedStateT[F, SA, SB, A]): IndexedStateT[F, SA, SB, A] =
        IndexedStateT.applyF(F.defer(fa.runF))
    }

  implicit def catsDataFunctorFilterForIndexedStateT[F[_], SA, SB](
    implicit
    ev1: Monad[F],
    ev2: FunctorFilter[F]
  ): FunctorFilter[IndexedStateT[F, SA, SB, *]] =
    new IndexedStateTFunctorFilter[F, SA, SB] {
      val F0 = ev1
      val FF = ev2
    }
}

sealed abstract private[data] class 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 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 }
}

sealed abstract private[data] class 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 }
}

sealed abstract private[data] class IndexedStateTInstances3 extends IndexedStateTInstances4 {
  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: Functor[F]
  ): Contravariant[IndexedStateT[F, *, SB, V]] =
    new IndexedStateTContravariant[F, SB, V] { implicit def F = F0 }

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

  implicit def catsDataBifunctorForIndexedStateT[F[_], SA](
    implicit F0: Functor[F]
  ): Bifunctor[IndexedStateT[F, SA, *, *]] =
    new IndexedStateTBifunctor[F, SA] { implicit def F = F0 }
}

sealed abstract private[data] class IndexedStateTInstances4 {
  implicit def catsDataStrongForIndexedStateT[F[_], V](implicit F0: Monad[F]): Strong[IndexedStateT[F, *, *, V]] =
    new IndexedStateTStrong[F, V] { implicit def F = F0 }
}

abstract private[data] class IndexedStateFunctions {

  /**
   * Instantiate an `IndexedState[S1, S2, A]`.
   *
   * Example:
   * {{{
   * scala> import cats.data.IndexedState
   *
   * scala> val is = IndexedState[Int, Long, String](i => (i + 1L, "Here is " + i))
   * scala> is.run(3).value
   * res0: (Long, String) = (4,Here is 3)
   * }}}
   */
  def apply[S1, S2, A](f: S1 => (S2, A)): IndexedState[S1, S2, A] =
    IndexedStateT.applyF(Now((s: S1) => Now(f(s))))
}

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

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

  /**
   * Return `a` and maintain the input state.
   */
  def pure[S, A](a: A): State[S, A] = State(s => (s, a))

  /**
   * Return `A`'s empty monoid value and maintain the input state.
   */
  def empty[S, A](implicit A: Monoid[A]): State[S, A] = pure(A.empty)

  /**
   * Modify the input state and return Unit.
   */
  def modify[S](f: S => S): State[S, Unit] = State(s => (f(s), ()))

  /**
   * Inspect a value from the input state, without modifying the state.
   */
  def inspect[S, T](f: S => T): State[S, T] = State(s => (s, f(s)))

  /**
   * Return the input state without modifying it.
   */
  def get[S]: State[S, S] = inspect(identity)

  /**
   * Set the state to `s` and return Unit.
   */
  def set[S](s: S): State[S, Unit] = State(_ => (s, ()))
}

sealed abstract private[data] class IndexedStateTFunctor[F[_], SA, SB] extends Functor[IndexedStateT[F, SA, SB, *]] {
  implicit def F: Functor[F]

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

sealed abstract private[data] class IndexedStateTContravariant[F[_], SB, V]
    extends Contravariant[IndexedStateT[F, *, SB, V]] {
  implicit def F: Functor[F]

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

sealed abstract private[data] class IndexedStateTBifunctor[F[_], SA] extends Bifunctor[IndexedStateT[F, SA, *, *]] {
  implicit def F: Functor[F]

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

sealed abstract private[data] class IndexedStateTProfunctor[F[_], V] extends Profunctor[IndexedStateT[F, *, *, V]] {
  implicit def F: Functor[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)
}

sealed abstract private[data] class IndexedStateTStrong[F[_], V]
    extends IndexedStateTProfunctor[F, V]
    with Strong[IndexedStateT[F, *, *, V]] {
  implicit def F: Monad[F]

  def first[A, B, C](fa: IndexedStateT[F, A, B, V]): IndexedStateT[F, (A, C), (B, C), V] =
    IndexedStateT {
      case (a, c) =>
        F.map(fa.run(a)) {
          case (b, v) =>
            ((b, c), v)
        }
    }

  def second[A, B, C](fa: IndexedStateT[F, A, B, V]): IndexedStateT[F, (C, A), (C, B), V] =
    first(fa).dimap((_: (C, A)).swap)(_.swap)
}

sealed abstract private[data] class IndexedStateTMonad[F[_], S]
    extends IndexedStateTFunctor[F, S, S]
    with Monad[IndexedStateT[F, S, S, *]] {
  implicit def F: Monad[F]

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

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

  def tailRecM[A, B](a: A)(f: A => IndexedStateT[F, S, S, Either[A, B]]): IndexedStateT[F, S, S, B] =
    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, _)) }
        }
    )
}

sealed abstract private[data] class IndexedStateTSemigroupK[F[_], SA, SB]
    extends SemigroupK[IndexedStateT[F, SA, SB, *]] {
  implicit def F: Monad[F]
  implicit def G: SemigroupK[F]

  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)))
}

sealed abstract private[data] class IndexedStateTContravariantMonoidal[F[_], S]
    extends ContravariantMonoidal[IndexedStateT[F, S, S, *]] {
  implicit def F: ContravariantMonoidal[F]
  implicit def G: Applicative[F]

  override def unit: IndexedStateT[F, S, S, Unit] =
    IndexedStateT.applyF(G.pure((s: S) => F.trivial[(S, Unit)]))

  override def contramap[A, B](fa: IndexedStateT[F, S, S, A])(f: B => A): IndexedStateT[F, S, S, B] =
    contramap2(fa, trivial)(((a: A) => (a, a)).compose(f))

  override def product[A, B](fa: IndexedStateT[F, S, S, A],
                             fb: IndexedStateT[F, S, S, B]): IndexedStateT[F, S, S, (A, B)] =
    contramap2(fa, fb)(identity)

  def contramap2[A, B, C](fb: IndexedStateT[F, S, S, B],
                          fc: IndexedStateT[F, S, S, C])(f: A => (B, C)): IndexedStateT[F, S, S, A] =
    IndexedStateT.applyF(
      G.pure(
        (s: S) =>
          ContravariantMonoidal.contramap2(G.map(fb.runF)(_.apply(s)), G.map(fc.runF)(_.apply(s)))(
            (tup: (S, A)) =>
              f(tup._2) match {
                case (b, c) => (G.pure((tup._1, b)), G.pure((tup._1, c)))
              }
          )(G, F)
      )
    )
}

sealed abstract private[data] class IndexedStateTAlternative[F[_], S]
    extends IndexedStateTMonad[F, S]
    with Alternative[IndexedStateT[F, S, S, *]] {
  def G: Alternative[F]

  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 empty[A]: IndexedStateT[F, S, S, A] =
    IndexedStateT.liftF[F, S, A](G.empty[A])(G)
}

sealed abstract private[data] class 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): IndexedStateT[F, S, S, A] = IndexedStateT.liftF(F.raiseError(e))

  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)))
}

private[this] trait IndexedStateTFunctorFilter[F[_], SA, SB] extends FunctorFilter[IndexedStateT[F, SA, SB, *]] {

  implicit def F0: Monad[F]
  def FF: FunctorFilter[F]

  def functor: Functor[IndexedStateT[F, SA, SB, *]] =
    IndexedStateT.catsDataFunctorForIndexedStateT(FF.functor)

  def mapFilter[A, B](fa: IndexedStateT[F, SA, SB, A])(f: A => Option[B]): IndexedStateT[F, SA, SB, B] =
    fa.flatMapF(a => FF.mapFilter(F0.pure(a))(f))
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy