0

应该Either使用参数化函数吗?

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>))
4

2 回答 2

3

问题在于,因为Iterable分支也得到 a T1,所以Function1不允许分支将其修复为Int(不仅仅是Function1; 具有用于协变和逆变类型参数的相同类型参数在类型推理引擎上往往很困难)。Iterable您可以通过添加更多类型参数并让比 更窄来坚持编译器允许这样做Function1

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>))
于 2014-12-03T01:05:55.767 回答
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>))
于 2014-12-03T01:05:05.320 回答