flatMap(func)与flatMap(func(_))

时间:2016-06-09 12:25:25

标签: scala

由于无法找到该问题,我感到非常惊讶。为什么这样,给定:

val p: Int => Option[Int] = Some(_)
List(1, 2, 3).flatMap(p)

我得到了:

<console>:14: error: type mismatch;
 found   : Int => Option[Int]
 required: Int => scala.collection.GenTraversableOnce[?]
       List(1, 2, 3).flatMap(p)

但是如果我用这个替换最后一行,它会按预期编译并运行:

List(1, 2, 3).flatMap(p(_))

我对这个问题的看法是,在p(_)的情况下,类型推断系统开始决定lambda的类型,以及它为Option[Int]找到适当的隐式转换的方式({{ 1}},我相信)。仅使用option2Iterable,该类型已知且不正确,因此未尝试转换(并且p没有转换Function1返回Option返回{{1} }})。

这个推理是对的吗?如果是这样,有什么理由我不应该将此报告为错误/问题吗?

编辑:一个新的转折:我看到Function1在一些(遗憾的)删除的评论中提到了(虽然这是关于编码风格)。令人惊讶的是,它与GenTraversableOnce一样有效。

2 个答案:

答案 0 :(得分:8)

当你输入List(1, 2, 3).flatMap(p(_))幕后所做的事情时,函数p会被生成并包含在另一个部分应用它的函数中 - 这意味着所有必要的隐式转换(如果有的话)将会也可以在这个新函数的主体内部应用。

当您键入List(1, 2, 3).flatMap(p)时,不会发生任何函数应用程序,并且您尝试传递与签名Int => Option[Int]不兼容的Int => GenTraversableOnce[Int],尽管范围包含来自{的隐式转换{1}}至Option[T],未定义从Iterable[T]Function1[Int, Option[Int]]的转换。

原因可能是因为任意arity的函数由于泛型而具有几乎无限的变化,并且由于Function1[Int, Iterable[Int]] s不共享超级,所以每个都需要相当多的含义。功能类型。

这是一个扩展Function的结构,足以实现flatMap的预期结果。然而,它使p已经模糊的签名更不清晰(更不清楚)。我相信,实现这种行为没有任何技术障碍,但签名的复杂性是scala-collections库经常受到欢迎的原因。

flatMap

答案 1 :(得分:4)

List(1, 2, 3).flatMap(p(_))

编译为:

List(1,2,3).flatMap(x => p(x))

由于p(x)正在返回Option[Int]flatMap需要GenTraversableOnce[Int],因此应用了scala.Option.option2Iterable

选项不会从GenTraversableOnce继承。要使此语法有效:

List(1,2,3).flatMap(p)

您需要从Int => Option[Int]隐式转换为Int => GenTraversableOnce[Int],如下所示:

import scala.collection.GenTraversableOnce

implicit def conv(c: Int => Option[Int]): Int => GenTraversableOnce[Int] = {
    a => Option.option2Iterable(c(a))
}
val p: Int => Option[Int] = Some(_)
List(1, 2, 3).flatMap(p)

对我而言,这不是一个错误,但我同意,它也不直观。