Scala Function.tupled与f.tupled的区别

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

我认为 map 后面跟着 flatten 总是可以替换成 flatMap,但尽管上述代码可以编译通过,下面这行却不行:

data flatMap Function.tupled(f)

2个回答

2
只有在返回Options时才能使用flatMap,因为通过隐式的option2Iterable将Option转换为Iterable。您的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接受一个返回Option的方法,并将其转换为PartialFunction,该函数不匹配原始函数返回None的位置。 collect接受部分函数,并在每个元素上定义时收集部分函数的值。


在我看来,data collect unlift(tupled(f)) 在这里更有意义。谢谢! - pathikrit

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()中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接