I have the following Scala code:
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)}
But, the last line is too verbose so I tried all of these and none of them compiles.
data flatMap f
data flatMap f.tupled
data flatMap Function.tupled(f)
data flatMap {f _}
data flatMap (f _).tupled
data flatMap f(_)
What am I doing wrong? The only thing that works is this:
(data map Function.tupled(f)).flatten
I thought a map followed by flatten can always be replaced by flatMap, but although the above line compiles, this does not:
data flatMap Function.tupled(f)
You can only use flatMap when returning Options because there is an implicit conversion from Option to Iterable by the implicit option2Iterable. The method flatMap on your List[(Int, Int)] expects a function from (Int, Int) to GenTraversableOnce[Int]. The compiler is having trouble identifying that implicit conversion as a viable option here. You can help the compiler along by explicitly specifying your generic parameters:
import Function._
data.flatMap[String, Iterable[String]](tupled(f))
//Or
data flatMap tupled[Int, Int, Iterable[String]](f)
Other formulations of the same idea might also allow the compiler to pick the correct types and implicits, even without the explicit generics:
data flatMap (tupled(f _)(_))
data.flatMap (f.tupled(f _)(_))
Finally, you might also want to play with collect together with unlift here, which can be a nice way to express this logic as well:
data collect unlift((f _).tupled)
data collect unlift(tupled(f))
Function.unlift takes a method that returns an Option and turns it into PartialFunction that doesn't match where the original function would return None. collect takes a partial function and collects the values of a the partial function if it is defined at each element.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With