类型推断:使用具有隐式类型转换的泛型方法

时间:2009-11-25 17:37:09

标签: generics scala types type-inference

问题是你要将List[Option[T]]平面地映射到List[T]

val l = List(Some("Hello"), None, Some("World"))

得到:

List(Hello, World)

但没有很好的解决方案:

l flatMap( o => o)
l flatMap identity[Option[String]]
l flatMap ( x => Option.option2Iterable(identity(x)))
for(x <- l; y <- x) yield y

由于从Option[T]Iterable[T]的所需类型转换,使用身份功能的明显解决方案无效:

l flatMap identity

<console>:6: error: type mismatch;
 found   : A
 required: Iterable[?]
       l flatMap identity

有解决这个问题的方法吗?

部分问题是,如果需要隐式类型转换,为什么类型推断器的工作方式不同?

(讨论this question about the identity function时出现了这个问题。)

2 个答案:

答案 0 :(得分:2)

Option扩展Iterable特征;我想知道他们为什么不首先这样做......

请注意,该示例在带有类型提示的scala 2.8 中不起作用:

scala> val l = List(Some("Hello"), None, Some("World"))
l: List[Option[java.lang.String]] = List(Some(Hello), None, Some(World))

scala> l.flatMap(identity) : List[String]
<console>:6: error: type mismatch;
 found   : A
 required: Traversable[?]
   l.flatMap(identity) : List[String]

答案 1 :(得分:2)

隐含没有问题。如果它是列表列表,您将无法将identity传递给mapflatMap。我们讨论map而不是flatMap,因为它更简单,所以我可以更好地解释我的想法。

identity的类型为(A) => Amap (A) => B的类型,其中A已知,因为它是对象的类型参数(即在List[String]中,它是String })。 identity的{​​{1}}和A的{​​{1}}都不知道。

现在,如果我们使用map类型的左侧来推断B的左侧,那么我们可以使用map的右侧来推断右侧identity。看一个周期? identity的类型为map的类型再次为map的类型。我很确定类型推理器可以避免循环,否则它可能会陷入无限循环。

事实上,人们可以查看Odersky等人的Programming in Scala页面355中类型推理器的详细信息。在方法应用程序identity中,它执行以下步骤:

  1. 它检查方法map(在我们的例子中是m(arg))是否具有已知类型(不,我们不知道m)。
  2. 检查参数map(我们案例中为B)是否具有已知类型(不,我们不知道arg)。
  3. 它拯救了。
  4. 所以,你必须提供一种类型。例如:

    identity

    在Scala 2.8上,类型推理器有点聪明,并且可以在不明确传递类型的情况下处理第二个命令。