2014-12-03 93 views
0

Either應該帶參數化功能嗎?Scala:帶參數化功能類型

case class FunOrSeq[T1, T2](e: Either[Function1[T1, T2], Iterable[T1]]) 

def f: Int => Int = x => x 

scala> FunOrSeq(Left(f)) 
<console>:11: error: type mismatch; 
found : scala.util.Left[Int => Int,Nothing] 
required: Either[T1 => Int,Iterable[T1]] 
      FunOrSeq(Left(f)) 

這是令人驚訝的,我 - 它的工作原理與明確的類型:

scala> case class FunOrSeq[T1, T2](e: Either[(Int => Int), Iterable[T1]]) 
defined class FunOrSeq 

scala> FunOrSeq(Left(f)) 
res6: FunOrSeq[Nothing,Nothing] = FunOrSeq(Left(<function1>)) 
+1

不是一個答案,但如果你在類型參數傳遞明確的'Left'以及你的第一個例子工程。 'FunOrSeq(Left [(Int => Int),Iterable [Int]](f))'看起來好像不能確定'[Int => Int,Nothing]'滿足'[T1 => Int,Iterable [T1]]' – Falmarri 2014-12-03 01:02:45

回答

3

的問題是,因爲Iterable分支也得到了T1,在Function1分支不允許修復它爲Int(它不只是Function1;具有用於兩個協變和逆變類型相同的類型參數在類型推斷引擎中爭論往往很難)。你能堅持,編譯器允許這種通過增加更多類型的參數,並讓IterableFunction1窄:

case class FunOrSeq[A, B, AA <: A](e: Either[A => B, Iterable[AA]]) 

scala> FunOrSeq(Left(f)) 
res0: FunOrSeq[Int,Int,Nothing] = FunOrSeq(Left(<function1>)) 

如果你希望他們真的是一樣的,你可以添加一個隱含迫使他們是一樣的:

case class FunOrSeq[A, B, AA <: A](e: Either[A => B, Iterable[AA]])(implicit ev: A =:= AA) 

scala> FunOrSeq(Left(f)) 
res1: FunOrSeq[Int,Int,Int] = FunOrSeq(Left(<function1>)) 
1

我不知道的原因是這裏的編譯器的決定背後有什麼,但事實證明,你有T1上都這兩者的任何一方都會混淆類型系統。如果添加一個參數使得Iterable [T3]與T1不同,它似乎就可以工作。

scala> case class FunOrSeq2[T1, T2, T3](e: Either[Function1[T1, T2], Iterable[T3]]) 
defined class FunOrSeq2 

scala> FunOrSeq2(Left(f2)) 
res12: FunOrSeq2[Int,String,Nothing] = FunOrSeq2(Left(<function1>))