Last active
November 19, 2018 10:33
-
-
Save MateuszKubuszok/38697a1cde333d7c44e6573ef1e474c8 to your computer and use it in GitHub Desktop.
ReverState in Scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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