Skip to content

Instantly share code, notes, and snippets.

@notxcain
Created May 16, 2017 08:05
Show Gist options
  • Select an option

  • Save notxcain/e15f30b1b8fd2de93359052644ef6d8d to your computer and use it in GitHub Desktop.

Select an option

Save notxcain/e15f30b1b8fd2de93359052644ef6d8d to your computer and use it in GitHub Desktop.
WIP
@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