Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
586 views
in Technique[技术] by (71.8m points)

scala - What are the hidden rules regarding the type inference in resolution of implicit conversions?

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...