Skip to content

Instantly share code, notes, and snippets.

@jto
Last active January 17, 2017 11:00
Show Gist options
  • Save jto/019d41cc8f40ed706de1e0692cfbc953 to your computer and use it in GitHub Desktop.
Save jto/019d41cc8f40ed706de1e0692cfbc953 to your computer and use it in GitHub Desktop.
object Test {
import scalaz._, Scalaz._
type FA[F[_], S, A] = FreeAp[λ[α => S => F[(S, α)]], A]
type Precepte[F[_], S, A] = Free[({ type L[A] = FA[F, S, A] })#L, A]
type UnmanagedState = List[String]
trait PreBuilder[F[_]]{
type Pre[A] = Precepte[F, UnmanagedState, A]
type St0[A] = UnmanagedState => F[(UnmanagedState, A)]
type St[A] = FA[F, UnmanagedState, A]
def apply[A](tag: String)(a: A)(implicit ap: Applicative[F]): Pre[A] = {
val fap = FreeAp.lift[St0, A] { s => (s, a).point[F] }
val p = Free.liftF[St, A](fap)
substep(tag)(p)
}
def suspend[A](tag: String)(fa: => F[A])(implicit ap: Functor[F]): Pre[A] = {
val fap = FreeAp.lift[St0, A]{ s => fa.map(s -> _) }
val p = Free.liftF[St, A](fap)
substep(tag)(p)
}
def substep[A](tag: String)(p: Pre[A]): Pre[A] = {
val go0 = new (St0 ~> St0) {
def apply[A](st: St0[A]) = s => st(s :+ tag)
}
val go = new (St ~> St) {
def apply[A](st: St[A]) = st.hoist(go0)
}
p.mapFirstSuspension(go)
}
def pure[A](a: A): Pre[A] =
Free.pure[St, A](a)
}
object Precepte {
def apply[F[_]] = new PreBuilder[F]{}
}
implicit def stepApplicative[F[_]: Applicative, S] =
new Applicative[λ[α => S => F[(S, α)]]] {
def point[A](a: => A): S => F[(S, A)] =
s => (s, a).point[F]
def ap[A, B](fa: => S => F[(S, A)])(f: => S => F[(S, A => B)]): S => F[(S, B)] = { s0 =>
val f0 = fa(s0)
val f1 = f(s0)
(f0 |@| f1) { (a, b) =>
(a._1, b._2(a._2)) // XXX: idiotic state management
}
}
}
def runAp[F[_], S](implicit A: Applicative[λ[α => S => F[(S, α)]]]) =
new (FA[F, S, ?] ~> λ[α => S => F[(S, α)]]) {
def apply[A](fa: FA[F, S, A]): S => F[(S, A)] = {
val refl = NaturalTransformation.refl[λ[α => S => F[(S, α)]]]
fa.foldMap[λ[α => S => F[(S, α)]]](refl)
}
}
implicit def mo[F[_]: Monad, S] =
new Monad[λ[α => S => F[(S, α)]]] {
def point[A](a: => A) = s => (s, a).point[F]
def bind[A, B](oa: S => F[(S, A)])(f: A => (S => F[(S, B)])): S => F[(S, B)] =
s0 => oa(s0).flatMap { case (s1, a) => f(a)(s1) }
}
import akka.pattern.after
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.concurrent.duration._
import akka.actor.ActorSystem
val system = ActorSystem("theSystem")
def f1 = after(duration = 10 second, using = system.scheduler)({println(System.currentTimeMillis); 1}.point[Future])
def f2 = after(duration = 10 second, using = system.scheduler)({println(System.currentTimeMillis); 2}.point[Future])
def go[F[_]: Monad](f1: => F[Int], f2: => F[Int]): UnmanagedState => F[(UnmanagedState, (Int, Int))] = {
import scalaz.syntax.applicative._
type Pre[A] = Precepte[F, UnmanagedState, A]
val p1: Pre[Int] = Precepte[F].suspend("p1")(f1)
val p2: Pre[Int] = Precepte[F].suspend("p2")(f2)
val p3: Pre[Int] = Precepte[F].substep("p3")(p1.flatMap(r1 => p2.map(r2 => r1 + r2)))
val nostate: UnmanagedState = Nil
type S0[α] = FA[F, UnmanagedState, α]
// implicit val freeMonad = Free.freeMonad[S0]
// implicit val freeAp = stepApplicative[Future, UnmanagedState]
// // p3.foldMap(run[S0]) // (List("p3", "p1", "p2"), 3)
(p1 |@| p2).tupled.foldMap[λ[α => UnmanagedState => F[(UnmanagedState, α)]]](runAp)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment