Created
June 27, 2018 08:40
-
-
Save muradm/9b202ee4d10a1e5b76adf5b80acb4bf5 to your computer and use it in GitHub Desktop.
Multi type type-class
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
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