Open union (Scala 2)

Oct 22, 2019 09:15



trait in[A, B] {
def inj(a: A): B
}
object in {
implicit def inSelf[A]: (A in A) = (a: A) => a
implicit def inHead[A, B]: (A in (A Either B)) = (a: A) => Left(a)
implicit def inRight[A, B, C](implicit r: (A in C)): (A in (B Either C)) =
(a: A) => Right(r.inj(a))
implicit def inLeft[A, B, C](implicit r: (A in B)): (A in (B Either C)) =
(a: A) => Left(r.inj(a))
}

def inj[B] = new {
def apply[A](a: A)(implicit r: (A in B)): B = r.inj(a)
}

def handle[A, B, C](a: (A Either B))(f: A => C): Option[B] =
a.fold(a => Function.const(None)(f(a)), Some(_))

type :|:[A, B] = Either[A, B]
type All = String :|: Int :|: Boolean :|: Double

def handleAll[A](a: A)(implicit r: (A in All)) =
handle(inj(a))(x => println(x + " : String"))
.flatMap(handle(_)(x => println(x + " : Int")))
.flatMap(handle(_)(x => println(x + " : Boolean")))
.map(x => println(x + " : Double"))

handleAll("a")
handleAll(1)
handleAll(true)
handleAll(1.0)

scala

Previous post Next post
Up