Scala Function.tupled 对比 f.tupled

Scala Function.tupled vs f.tupled

我有以下 Scala 代码:

def f(x: Int, y: Int): Option[String] = x*y match {
    case 0 => None
    case n => Some(n.toString)
}

val data = List((0, 1), (1, 0), (2, 3), (4, -1))

data flatMap {case (x, y) => f(x, y)}

但是,最后一行太冗长了,所以我尝试了所有这些并且 none 编译了它们。

data flatMap f

data flatMap f.tupled

data flatMap Function.tupled(f)

data flatMap {f _}

data flatMap (f _).tupled

data flatMap f(_)

我做错了什么?唯一有效的是:

(data map Function.tupled(f)).flatten

我认为 map 后跟 flatten 总是可以替换为 flatMap,但是虽然上面的行编译了,但这并没有:

data flatMap Function.tupled(f)

您只能在 returning Options 时使用 flatMap,因为隐式 [=17] 存在从 OptionIterable 的隐式转换=]. List[(Int, Int)] 上的方法 flatMap 需要一个从 (Int, Int)GenTraversableOnce[Int] 的函数。编译器无法将隐式转换识别为此处的可行选项。您可以通过显式指定通用参数来帮助编译器:

import Function._
data.flatMap[String, Iterable[String]](tupled(f))
//Or
data flatMap tupled[Int, Int, Iterable[String]](f)

相同想法的其他表述也可能允许编译器选择正确的类型和隐式,即使没有显式泛型:

data flatMap (tupled(f _)(_))
data.flatMap (f.tupled(f _)(_))

最后,您可能还想在这里把 collectunlift 一起玩,这也是表达这个逻辑的好方法:

data collect unlift((f _).tupled)
data collect unlift(tupled(f))

Function.unlift 采用 return 一个 Option 的方法并将其转换为 PartialFunction 与原始函数 return 不匹配的地方Nonecollect 采用偏函数并收集偏函数的值(如果在每个元素处都定义了偏函数)。

为了进一步说明上面非常有用的答案,如果您使用 collect,您可以更进一步,将函数 f 重写为部分函数:

val f: PartialFunction[(Int, Int), String] = {
  case (x, y) if x*y != 0 => (x*y).toString
}

然后您可以这样处理您的数据:

data collect f

一般来说,任何 return 作为 Option 的函数都可以 re-written 作为偏函数。在某些情况下,这会变得更整洁,因为您的 case 表达式更少,并且不必将 return 值包装在 Some().