Created
May 16, 2017 08:05
-
-
Save notxcain/e15f30b1b8fd2de93359052644ef6d8d to your computer and use it in GitHub Desktop.
WIP
This file contains hidden or 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
| @algebra | |
| trait Ag[F[_]] { | |
| def mate(name: String): F[Unit] | |
| def feed(food: String): F[Unit] | |
| def kill: F[Unit] | |
| } | |
| sealed trait AgEvent | |
| case class AgBorn(name: String) extends AgEvent | |
| case class AgAte(food: String) extends AgEvent | |
| case object AgDied extends AgEvent | |
| object EventsourcedAg { | |
| case class State(spouse: Option[String]) | |
| def zero: EventsourcedAg = EventsourcedAg(None) | |
| } | |
| case class EventsourcedAg(state: Option[State]) extends Ag[(Seq[AgEvent], ?)] { | |
| override def mate(name: String): (Seq[AgEvent], Unit) = state match { | |
| case Some(_) => (Seq.empty, ()) | |
| case None => (Seq(AgBorn(name)), ()) | |
| } | |
| override def feed(food: String): (Seq[AgEvent], Unit) = state match { | |
| case Some(value) if value.spouse.isEmpty => | |
| (Seq(AgAte(food)), ()) | |
| case None => | |
| (Seq.empty, ()) | |
| } | |
| override def kill: (Seq[AgEvent], Unit) = state match { | |
| case Some(_) => | |
| (Seq(AgDied), ()) | |
| case None => | |
| (Seq.empty, ()) | |
| } | |
| } | |
| final case class AgId(value: String) extends AnyVal | |
| object Identified { | |
| final case class IdentfiedEvent[I, E](agId: I, agEvent: E) | |
| type F[M[_[_]], I, E, A] = | |
| M[(Seq[E], ?)] => I => (Seq[IdentfiedEvent[I, E]], A) | |
| def apply[M[_[_]], I, E](implicit M: Algebra[M]): M[F[M, I, E, ?]] = | |
| M.fromFunctionK[F[M, I, E, ?]] { | |
| new FunctionK[M.Out, F[M, I, E, ?]] { | |
| override def apply[A](fa: M.Out[A]): F[M, I, E, A] = { s => id => | |
| val (es, a) = M.toFunctionK(s)(fa) | |
| (es.map(IdentfiedEvent(id, _)), a) | |
| } | |
| } | |
| } | |
| } | |
| object Runtime { | |
| def deploy[M[_[_]], I, E](m: M[F[M, I, E, ?]], zero: M[(Seq[E], ?)])( | |
| implicit M: Algebra[M]): I => M[Id] = { | |
| val f = M.toFunctionK[F[M, I, E, ?]](m) | |
| i => | |
| M.fromFunctionK(new ~>[M.Out, Id] { | |
| override def apply[A](fa: M.Out[A]): Id[A] = { | |
| val x: F[M, I, E, A] = f(fa) | |
| val s = x(zero) | |
| s(i)._2 | |
| } | |
| }) | |
| } | |
| def deploy2[M[_[_]], I, E](m: M[F[M, I, E, ?]], zero: M[(Seq[E], ?)])( | |
| implicit M: Algebra[M]): M[Kleisli[Id, I, ?]] = { | |
| M.fromFunctionK(new ~>[M.Out, Kleisli[Id, I, ?]] { | |
| private val f = M.toFunctionK[F[M, I, E, ?]](m) | |
| override def apply[A](fa: M.Out[A]): Kleisli[Id, I, A] = | |
| Kleisli[Id, I, A] { i: I => | |
| val x: F[M, I, E, A] = f(fa) | |
| val s = x(zero) | |
| s(i)._2 | |
| } | |
| }) | |
| } | |
| } | |
| object run { | |
| val identified = Identified[Ag, AgId, AgEvent] | |
| val zero = EventsourcedAg.zero | |
| val deployed = | |
| Runtime.deploy(identified, zero) | |
| deployed(AgId("foo")).feed("apple") | |
| val deployed2 = | |
| Runtime.deploy2(identified, zero) | |
| deployed2.feed("apple").run(AgId("foo")) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment