TL;DR: I thought that if the following compiles:
implicitly[X => Y]
than so will this:
(??? :X) :Y
It turns out I was wrong. Backstory: I toyed with an implementation of type unions:
private[this] val cast = identity[Any] _
abstract class TypeUnionLevel4Implicits {
implicit def implicitUnionUnification[L, R, U <: Any | Any](implicit left :L => U, right :R => U) :(L | R) => U =
left.asInstanceOf[(L | R) => U]
}
sealed abstract class TypeUnionLevel3Implicits extends TypeUnionLevel4Implicits {
implicit def implicitRightComposedUnionMember[X, L, R <: Any | Any](implicit right :X => R) :X => (L | R) =
right.asInstanceOf[X => (L | R)]
}
sealed abstract class TypeUnionLevel2Implicits extends TypeUnionLevel3Implicits {
implicit def implicitLeftComposedUnionMember[X, L <: Any | Any, R](implicit left :X => L) :X => (L | R) =
left.asInstanceOf[X => (L | R)]
}
sealed abstract class TypeUnionLevel1Implicits extends TypeUnionLevel2Implicits {
implicit def implicitRightUnionMember[L, R] :R => (L | R) = cast.asInstanceOf[R => (L | R)]
}
abstract class TypeUnionImplicits private[slang] extends TypeUnionLevel1Implicits {
implicit def implicitLeftUnionMember[L, R] :L => (L | R) = cast.asInstanceOf[L => (L | R)]
}
object union extends TypeUnionImplicits {
type |[+L, +R]
}
Testing:
implicitly[String => (String | Int)]
implicitly[String => (Int | String)]
implicitly[(String | Int) => (Int | String)]
implicitly[String => (Int | String | Double)]
implicitly[String => (String | Int | Double | Short)]
implicitly[String => (Short | (Double | (Int | String)))]
implicitly[(String | Int | Double | Short) => (Short | Double | Int | String)]
Compiles! Success! Or is it?
val left = "left" :String | Int
val right = "right" :Int | String
val swap = (left :String | Int) :Int | String
val middle = "middle" :Int | String | Double
val farLeft = "farLeft" :String | Int | Double | Short
val farRight = "farRight" :Short | (Double | (Int | String))
val shuffle = farLeft :Short | Double | Int | String
compile...compile...compile...
Information:(14, 19) typist.this.`package`.implicitUnionUnification is not a valid implicit value for String | Int => Int | String because:
not enough arguments for method implicitUnionUnification: (implicit left: L => U, right: R => U): L | R => U.
Unspecified value parameter right.
val swap = (left :String | Int) :Int | String
Error:(14, 19) type mismatch;
found : String | Int
required: Int | String
val swap = (left :String | Int) :Int | String
FFFFuuu....
I opened an issue at /dev/null because it surely must be a bug. But it looks just so plain and basic stuff, that it seems there must be a way to work around it.
What I tried:
direct implicit conversions as normal methods, not function-returning ones;
an intermediate implicit class
class TypeUnionMember[X, U]
with the implicit methods above returning it instead of X=>U
, together with one top level implicit providing X=>U
when TypeUnionMember[X, U]
implicit exists:
implicit def widenToTypeUnion[X, U](implicit unify :TypeUnionMember[X, U]) :X => U = cast.asInstanceOf[X, U]
The latter proved interesting and by interesting I mean frustrating: the logs sad that widenToTypeUnion
is an invalid implicit for String => String | Int
because an implicit TypeUnionMember[String, Nothing]
cannot be found. What?
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…