5

我有以下 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)}

但是,最后一行太冗长了,所以我尝试了所有这些,但都没有编译。

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

我认为 amap后面的flatten总是可以替换为flatMap,但是尽管上面的行编译了,但这不是:

data flatMap Function.tupled(f)

4

2 回答 2

2

您只能flatMap在返回时使用,Options因为隐式从OptionIterable隐式转换option2IterableflatMap您的方法List[(Int, Int)]需要一个函数 from (Int, Int)to 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 _)(_))

最后,你可能还想和这里collect一起玩unlift,这也是表达这个逻辑的好方法:

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

Function.unlift采用返回 an 的方法并将Option其转换为PartialFunction与原始函数返回的位置不匹配的方法Nonecollect接受一个偏函数并收集偏函数的值(如果它在每个元素处定义)。

于 2015-04-30T01:26:17.833 回答
0

为了进一步获得上述非常有用的答案,如果您使用collect,您可以更进一步,将您的函数 f 重写为偏函数:

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

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

data collect f

通常,任何返回 Option 的函数都可以重写为偏函数。在某些情况下,这会更简洁,因为您的case表达式更少,并且不必将返回值包装在Some().

于 2017-02-01T19:59:59.330 回答