Skip to content

Instantly share code, notes, and snippets.

@muradm
Created June 27, 2018 08:40
Show Gist options
  • Save muradm/9b202ee4d10a1e5b76adf5b80acb4bf5 to your computer and use it in GitHub Desktop.
Save muradm/9b202ee4d10a1e5b76adf5b80acb4bf5 to your computer and use it in GitHub Desktop.
Multi type type-class
import shapeless.{:+:, CNil, Coproduct, Generic, Lazy}
object TestCop1 extends App {
sealed trait MyState
case class MyState1() extends MyState
// case class MyState2() extends MyState
// case class MyState3() extends MyState
sealed trait MyEvent
case class MyEvent1() extends MyEvent
case class MyEvent2() extends MyEvent
case class MyEvent3() extends MyEvent
object EventHandlersModule {
implicit val state1Event1: MyEventHandler[MyState1, MyEvent1] = (s: MyState1, e: MyEvent1) => println(s"state1Event1: $e => $s")
implicit val state1Event2: MyEventHandler[MyState1, MyEvent2] = (s: MyState1, e: MyEvent2) => println(s"state1Event2: $e => $s")
implicit val state1Event3: MyEventHandler[MyState1, MyEvent3] = (s: MyState1, e: MyEvent3) => println(s"state1Event3: $e => $s")
}
trait MyEventHandler[S <: MyState, E <: MyEvent] {
def handle(s: S, e: E): Unit
}
object MyEventHandler {
def apply[S <: MyState, E <: MyEvent](implicit EH: MyEventHandler[S, E]): MyEventHandler[S, E] = EH
def handle[S <: MyState, E <: MyEvent](s: S, e: E)(implicit EH: MyEventHandler[S, E]): Unit = apply[S, E].handle(s, e)
trait CopSHandler[S <: Coproduct, E <: MyEvent] { def handle(s: S, e: E): Unit }
object CopSHandler {
implicit def cnil[E <: MyEvent]: CopSHandler[CNil, E] = (_: CNil, e: E) => throw new IllegalArgumentException(s"CNil state for $e")
}
trait CopEHandler[S <: MyState, E <: Coproduct] { def handle(s: S, e: E): Unit }
object CopEHandler {
implicit def cnil[S <: MyState]: CopEHandler[S, CNil] = (s: S, _: CNil) => throw new IllegalArgumentException(s"CNil event for $s")
}
trait CopHandler[SR <: Coproduct, ER <: Coproduct] { def handle(s: SR, e: ER): Unit }
object CopHandler {
implicit val cnil: CopHandler[CNil, CNil] = (_: CNil, _: CNil) => throw new IllegalArgumentException(s"CNil event CNil state")
implicit def cnilS[SR <: Coproduct]: CopHandler[SR, CNil] = (sr: SR, _: CNil) => throw new IllegalArgumentException(s"CNil event for $sr")
implicit def cnilR[ER <: Coproduct]: CopHandler[CNil, ER] = (_: CNil, er: ER) => throw new IllegalArgumentException(s"CNil state for $er")
}
private class CopHandlerInst[S <: MyState, SR <: Coproduct, E <: MyEvent, ER <: Coproduct](h: MyEventHandler[S, E],
ch: CopHandler[SR, ER],
chS: CopSHandler[SR, E],
chE: CopEHandler[S, ER])
extends CopHandler[S :+: SR, E :+: ER] {
override def handle(sr: S :+: SR, er: E :+: ER): Unit = (sr.select[S], er.select[E]) match {
case (Some(s), Some(e)) => h.handle(s, e)
case (Some(s), None) => er.eliminate(e => h.handle(s, e), _er => chE.handle(s, _er))
case (None, Some(e)) => sr.eliminate(s => h.handle(s, e), _sr => chS.handle(_sr, e))
case (None, None) => throw new IllegalArgumentException(s"select both None")
}
}
implicit def copEH[S <: MyState, E <: MyEvent, ER <: Coproduct](implicit h: MyEventHandler[S, E], t: Lazy[CopEHandler[S, ER]]): CopEHandler[S, E :+: ER] =
new CopEHandler[S, E :+: ER] {
override def handle(s: S, er: E :+: ER): Unit = er.eliminate(e => h.handle(s, e), _er => t.value.handle(s, _er))
}
implicit def copSH[S <: MyState, SR <: Coproduct, E <: MyEvent](implicit h: MyEventHandler[S, E], t: Lazy[CopSHandler[SR, E]]): CopSHandler[S :+: SR, E] =
new CopSHandler[S :+: SR, E] {
override def handle(sr: S :+: SR, e: E): Unit = sr.eliminate(s => h.handle(s, e), _sr => t.value.handle(_sr, e))
}
implicit def copH[S <: MyState, SR <: Coproduct, E <: MyEvent, ER <: Coproduct](implicit h: MyEventHandler[S, E] ,
ch: CopHandler[SR, ER],
chS: CopSHandler[SR, E],
chE: CopEHandler[S, ER]): CopHandler[S :+: SR, E :+: ER] =
new CopHandlerInst(h, ch, chS, chE)
implicit def genH[SR <: Coproduct, ER <: Coproduct](implicit genSR: Generic.Aux[MyState, SR],
genER: Generic.Aux[MyEvent, ER],
cop: Lazy[CopHandler[SR, ER]]): MyEventHandler[MyState, MyEvent] =
new MyEventHandler[MyState, MyEvent] {
override def handle(s: MyState, e: MyEvent): Unit = cop.value.handle(genSR.to(s), genER.to(e))
}
}
// println(implicitly[MyEventHandler.CopSHandler[CNil, MyEvent1]])
// println(implicitly[MyEventHandler.CopSHandler[CNil, MyEvent2]])
// println(implicitly[MyEventHandler.CopEHandler[MyState1, CNil]])
// println(implicitly[MyEventHandler.CopSHandler[CNil, MyEvent]])
// println(implicitly[MyEventHandler.CopEHandler[MyState, CNil]])
//
// println(MyEventHandler.copSH[MyState1, CNil, MyEvent1])
// println(MyEventHandler.copEH[MyState1, MyEvent1, MyEvent2 :+: CNil])
// println(MyEventHandler.copEH[MyState1, MyEvent2, CNil])
//
// println(MyEventHandler.copH[MyState1, CNil, MyEvent1, MyEvent2 :+: CNil])
//
// println(MyEventHandler.genH[MyState1 :+: CNil, MyEvent1 :+: MyEvent2 :+: CNil])
// println(implicitly[MyEventHandler.CopHandler[CNil, MyEvent1 :+: CNil]])
// println(implicitly[MyEventHandler.CopHandler[MyState1 :+: CNil, CNil]])
// println(implicitly[MyEventHandler.CopHandler[MyState1 :+: CNil, MyEvent1 :+: CNil]])
// println(implicitly[MyEventHandler[MyState, MyEvent]])
import EventHandlersModule._
val e1 = MyEvent1()
val s1 = MyState1()
MyEventHandler.handle(s1, e1)
val e2: MyEvent = MyEvent2()
val s2: MyState = MyState1()
MyEventHandler.handle(s2, e2)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment