/
t10213.scala
53 lines (39 loc) · 1.23 KB
/
t10213.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import scala.language.higherKinds
final case class Coproduct[F[_], G[_], A](run: Either[F[A], G[A]])
object Coproduct {
sealed trait Builder {
type Out[_]
}
sealed trait :++:[F[_], G[_]] extends Builder {
type Out[A] = Coproduct[F, G, A]
}
sealed trait :+:[F[_], B <: Builder] extends Builder {
type Out[A] = Coproduct[F, B#Out, A]
}
}
trait Inject[F[_], H[_]] {
def inj[A](fa: F[A]): H[A]
}
object Inject {
import Coproduct._
implicit def reflexiveInject[F[_]]: Inject[F, F] =
new Inject[F, F] {
def inj[A](fa: F[A]): F[A] = fa
}
implicit def injectLeft[F[_], G[_]]: Inject[F, (F :++: G)#Out] =
new Inject[F, (F :++: G)#Out] {
def inj[A](fa: F[A]): Coproduct[F, G, A] = Coproduct(Left(fa))
}
implicit def injectRight[F[_], G[_], H[_]](implicit I: Inject[F, H]): Inject[F, (G :++: H)#Out] =
new Inject[F, (G :++: H)#Out] {
def inj[A](fa: F[A]): Coproduct[G, H , A] = Coproduct(Right(I.inj(fa)))
}
}
object Test1 {
import Coproduct.{:++:, :+:}
class Foo[A]
class Bar[A]
class Baz[A]
implicitly[Inject[Baz, (Foo :+: Bar :++: Baz)#Out]]
implicitly[Inject[Baz, ({ type Out[A] = Coproduct[Foo, ({ type Out1[a] = Coproduct[Bar, Baz, a] })#Out1, A] })#Out]]
}