Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
ReverState in Scala
// based on http://pavkin.ru/reverse-state-monad-in-scala-is-it-possible/
import $ivy.`org.typelevel::cats-core:1.4.0`, cats._, cats.implicits._
//import $plugin.$ivy.`org.spire-math::kind-projector:0.9.4`
//import $plugin.$ivy.`com.olegpy::better-monadic-for:0.2.4`
///
{
class ReverseState[S, A](val runF: Eval[Eval[S] => (Eval[S], Eval[A])]) {
def map[B](f: A => B): ReverseState[S, B] =
new ReverseState[S, B](
runF.map(run =>
s =>
run(s) match {
case (next, a) => next -> a.map(f)
})
)
def flatMap[B](f: Eval[A] => ReverseState[S, B]): ReverseState[S, B] =
ReverseState[S, B]({ s: Eval[S] =>
new {
lazy val pastPair : Eval[(Eval[S], Eval[A])] = Eval.defer(run(future))
lazy val past : Eval[S] = pastPair.flatMap(_._1)
lazy val a : Eval[A] = pastPair.flatMap(_._2)
lazy val futurePair: Eval[(Eval[S], Eval[B])] = Eval.defer(f(a).run(s))
lazy val future : Eval[S] = futurePair.flatMap(_._1)
lazy val b : Eval[B] = futurePair.flatMap(_._2)
val result: (Eval[S], Eval[B]) = past -> b
}.result
})
def run(s: Eval[S]): Eval[(Eval[S], Eval[A])] = runF.map(_(s))
def runA(s: Eval[S]): Eval[A] = run(s).flatMap(_._2)
}
object ReverseState {
def apply[S, A](fn: Eval[S] => (Eval[S], Eval[A])): ReverseState[S, A] =
new ReverseState(Eval.later(s => fn(s)))
}
}
////
def insert(ea: Eval[Int]): ReverseState[List[Int], Int] =
ReverseState[List[Int], Int] { es =>
val es1 = for {
s <- es
a <- ea
_ = println(s"s = $s")
_ = println(s"a = $a")
_ = println()
} yield s :+ a
es1 -> ea
}
insert(Eval.now(1)).flatMap { i =>
insert(i.map(_ + 1)).flatMap { j =>
insert(j.map(_ + 1))
}
}.run(Eval.now(List())).value._1.value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.