2017-07-07 67 views
3

的隱式轉換考慮下面的例子:Scala的容器嵌套類型

case class A() 

case class B() 

object Conversions { 
    implicit def aToB(a: A): B = B() 

    implicit def convert[U, T](seq: Seq[U])(implicit converter: U => T): Seq[T] = { 
    seq.map(converter) 
    } 
} 

object Main { 
    import Conversions._ 

    def main(args: Array[String]): Unit = { 

    val sa = Seq(A()) 

    def example(): Seq[B] = sa 
    } 
} 

這個例子將不會被階編譯器爲2.11.8版編譯。我確實與IntelliJ IDEA的編譯,但實際上的想法並不在飛行中產生的錯誤,並表示隱含用於轉換: Screenshot from Intellij Idea
要解決這個問題,我已經使用這裏所描述的方法: "Scala: Making implicit conversion A->B work for Option[A] -> Option[B]"
我的代碼開始看起來如下:

case class A() 

case class B() 

object Conversions { 
    implicit def aToB(a: A): B = B() 

    trait ContainerFunctor[Container[_]] { 
    def map[A, B](container: Container[A], f: A => B): Container[B] 
    } 

    implicit object SeqFunctor extends ContainerFunctor[Seq] { 
    override def map[A, B](container: Seq[A], f: (A) => B): Seq[B] = { 
     Option(container).map(_.map(f)).getOrElse(Seq.empty[B]) 
    } 
    } 

    implicit def functorConvert[F[_], A, B](x: F[A])(implicit f: A => B, functor: ContainerFunctor[F]): F[B] = functor.map(x, f) 
} 

object Main { 

    import Conversions._ 

    def main(args: Array[String]): Unit = { 

    val sa = Seq(A()) 

    def example(): Seq[B] = sa 
    } 
} 

此代碼編譯良好,並根據需要工作。

我的問題是:
爲什麼第一種方法編譯失敗?
這是否有點類似擦除,如果是的話,如何使用Functor幫助它?
編譯器如何解決這兩種情況下的含義?

回答

3

爲什麼第一種方法無法編譯?

I've opened a bug for this issue

這似乎是隱式搜索中的編譯器怪癖。由於您提供convert方法轉換Seq[A] => Seq[B],編譯器無法正確對齊類型。這是Ytyper-debug編制的輸出:

| [search #3] start `[U, T](seq: Seq[U])(implicit converter: U => T)Seq[T]` inferring type T, searching for adaptation to pt=A => T (silent: method example in Test) implicits disabled 
| [search #3] considering aToB 
| |-- { ((a: A) => Conversions.aToB(a)) } : pt=A => ? EXPRmode (silent: method example in Test) implicits disabled 
| | |-- ((a: A) => Conversions.aToB(a)) : pt=A => ? EXPRmode (silent: method example in Test) implicits disabled 
| | | |-- Conversions.aToB(a) EXPRmode (silent: value $anonfun in Test) implicits disabled 
| | | | |-- Conversions.aToB BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value $anonfun in Test) implicits disabled 
| | | | | \-> (a: A)B 
| | | | |-- a : pt=A BYVALmode-EXPRmode (silent: value $anonfun in Test) implicits disabled 
| | | | | \-> A 
| | | | \-> B 
| | | \-> A => B 
| | \-> A => B 
| [adapt] aToB adapted to { ((a: A) => Conversions.aToB(a)) } based on pt A => T 
| [search #3] solve tvars=?T, tvars.constr= >: B 
| solving for (T: ?T) 
| [search #3] success inferred value of type A => =?B is SearchResult({ 
|  ((a: A) => Conversions.aToB(a)) 
| }, TreeTypeSubstituter(List(type T),List(B))) 
| solving for (A: ?A) 
| solving for (A: ?A) 
| solving for (A: ?A) 
| solving for (A: ?A) 
| [search #3] considering $conforms 
| solving for (A: ?A) 
| [adapt] $conforms adapted to [A]=> <:<[A,A] based on pt A => T 
| [search #3] solve tvars=?T, tvars.constr= >: A 
| solving for (T: ?T) 
| [search #3] success inferred value of type A => =?A is SearchResult(scala.Predef.$conforms[A], TreeTypeSubstituter(List(type T),List(A))) 

這似乎是搜索#3是努力適應conforms<:<),這需要從A => BA => A整個隱含的搜索。如果我與-Yno-predef編譯,隱式轉換成功:

| | |-- [U, T](seq: Seq[U])(implicit converter: U => T)Seq[T] : pt=Seq[B] EXPRmode (silent: method example in Test) implicits disabled 
| | | [search #4] start `[U, T](seq: Seq[U])(implicit converter: U => T)Seq[T]`, searching for adaptation to pt=A => B (silent: method example in Test) implicits disabled 
| | | [search #4] considering aToB 
| | | |-- { ((a: A) => Conversions.aToB(a)) } : pt=A => B EXPRmode (silent: method example in Test) implicits disabled 
| | | | |-- ((a: A) => Conversions.aToB(a)) : pt=A => B EXPRmode (silent: method example in Test) implicits disabled 
| | | | | |-- Conversions.aToB(a) : pt=B EXPRmode (silent: value $anonfun in Test) implicits disabled 
| | | | | | |-- Conversions.aToB BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value $anonfun in Test) implicits disabled 
| | | | | | | \-> (a: A)B 
| | | | | | |-- a : pt=A BYVALmode-EXPRmode (silent: value $anonfun in Test) implicits disabled 
| | | | | | | \-> A 
| | | | | | \-> B 
| | | | | \-> A => B 
| | | | \-> A => B 
| | | [adapt] aToB adapted to { ((a: A) => Conversions.aToB(a)) } based on pt A => B 
| | | [search #4] success inferred value of type A => B is SearchResult({ 
| | |  ((a: A) => Conversions.aToB(a)) 
| | | },) 
| | | |-- [U, T](seq: Seq[U])(implicit converter: U => T)Seq[T] : pt=Seq[B] EXPRmode (silent: method example in Test) implicits disabled 
| | | | \-> Seq[B] 
| | | [adapt] [U, T](seq: Seq[U])(implicit converter: U => T)Seq[T] adapted to [U, T](seq: Seq[U])(implicit converter: U => T)Seq[T] based on pt Seq[B] 
| | | \-> Seq[B] 
| | [adapt] Seq[A] adapted to [U, T](seq: Seq[U])(implicit converter: U => T)Seq[T] based on pt Seq[B] 
| | \-> Seq[B] 
| \-> [def example]()Seq[B] 

這是主題相關的類型擦除,如果是,如何 函子的使用與它幫助?

第二個例子的作品,因爲你現在鋪設明確如何使用Functor型類Seq[A]Seq[B]映射,因此當編譯器看到一個Seq[A],它有一個隱含的將其轉換爲Seq[B]

def example(): Seq[B] = Conversions.functorConvert[Seq, A, B](sa)({ 
     ((a: A) => Conversions.aToB(a)) 
}, Conversions.SeqFunctor); 

注意你需要從雙方一A => B轉換和Functor[Seq]能夠全部A點地圖交給他們轉換爲B s,這是它​​不使用conversions.aToB

+0

感謝您的回覆。完美的解釋。 –

+0

@ andrii.ilin我的解釋實際上是有缺陷的,因爲我在第一個例子中錯過了轉換'Seq [A] => Seq [B]'的'convert'方法。現在挖掘它。 –

+0

我以爲你的第一個解釋涵蓋了這一點。仍然感謝您的解釋。 –