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

hedgehog.predef.State.scala Maven / Gradle / Ivy

There is a newer version: 0.11.0
Show newest version
package hedgehog.predef

case class StateT[M[_], S, A](run: S => M[(S, A)]) {

  def eval(s: S)(implicit F: Functor[M]): M[A] =
    F.map(run(s))(_._2)

  def exec(s: S)(implicit F: Functor[M]): M[S] =
    F.map(run(s))(_._1)

  def map[B](f: A => B)(implicit F: Functor[M]): StateT[M, S, B] =
    StateT(s => F.map(run(s))(x => x._1 -> f(x._2)))

  def flatMap[B](f: A => StateT[M, S, B])(implicit F: Monad[M]): StateT[M, S, B] =
    StateT(s => F.bind(run(s))(x => f(x._2).run(x._1)))

  def hoist[N[_], B](f: M[(S, A)] => N[(S, B)]): StateT[N, S, B] =
    StateT(s => f(run(s)))
}

abstract class StateTImplicits1 {

  implicit def StateTFunctor[M[_], S](implicit F: Functor[M]): Functor[StateT[M, S, *]] =
    new Functor[StateT[M, S, *]] {
      override def map[A, B](fa: StateT[M, S, A])(f: A => B): StateT[M, S, B] =
        fa.map(f)
    }
}

abstract class StateTImplicits2 extends StateTImplicits1 {

  implicit def StateTApplicative[M[_], S](implicit F: Monad[M]): Applicative[StateT[M, S, *]] =
    new Applicative[StateT[M, S, *]] {

      def point[A](a: => A): StateT[M, S, A] =
        StateT(s => F.point((s, a)))

      def ap[A, B](fa: => StateT[M, S, A])(f: => StateT[M, S, A => B]): StateT[M, S, B] =
        StateT.StateTMonad[M, S].bind(f)(ab =>
        StateT.StateTFunctor[M, S].map(fa)(a =>
          ab(a)
        ))
    }
}

object StateT extends StateTImplicits2 {

  implicit def StateTMonad[M[_], S](implicit F: Monad[M]): Monad[StateT[M, S, *]] =
    new Monad[StateT[M, S, *]] {

      override def map[A, B](fa: StateT[M, S, A])(f: A => B): StateT[M, S, B] =
        fa.map(f)

      override def point[A](a: => A): StateT[M, S, A] =
        StateTApplicative(F).point(a)

      override def ap[A, B](fa: => StateT[M, S, A])(f: => StateT[M, S, A => B]): StateT[M, S, B] =
        StateTApplicative(F).ap(fa)(f)

      override def bind[A, B](fa: StateT[M, S, A])(f: A => StateT[M, S, B]): StateT[M, S, B] =
        fa.flatMap(f)
    }

}

trait StateTOpt[M[_]] {

  // Just to give ol' scala type-inference a helping hand...
  def traverse[S, A, B](l: List[A])(f: A => StateT[M, S, B])(implicit F: Monad[M]): StateT[M, S, List[B]] =
    hedgehog.predef.traverse[StateT[M, S, *], A, B](l)(f)

  def apply[S, A](f: S => M[(S, A)]): StateT[M, S, A] =
    StateT(f)

  def state[S, A](f: S => (S, A))(implicit F: Applicative[M]): StateT[M, S, A] =
    StateT(s => F.point(f(s)))

  def lift[S, A](m: M[A])(implicit F: Functor[M]): StateT[M, S, A] =
    StateT(s => F.map(m)(a => (s, a)))

  def point[S, A](a: A)(implicit F: Applicative[M]): StateT[M, S, A] =
    StateT(s => F.point((s, a)))

  def get[S](implicit F: Applicative[M]): StateT[M, S, S] =
    StateT(s => F.point((s, s)))

  def put[S](s: S)(implicit F: Applicative[M]): StateT[M, S, Unit] =
    StateT(_ => F.point((s, ())))

  def modify[S](f: S => S)(implicit F: Applicative[M]): StateT[M, S, Unit] =
    StateT(s => F.point((f(s), ())))
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy