Scala: Defining a Function as the Right Type

I played with Scala code and encountered a compiler error that I don't understand. The code generates a vector of Ints pairs and then tries to filter it.

val L = for (x <- (1 to 5)) yield (x, x * x) val f = (x: Int, y: Int) => x > 3 println(L.filter(f)) 

The compiler complains trying to use f as an argument to the filter method with the creator error message compiler:

 error: type mismatch; found : (Int, Int) => Boolean required: ((Int, Int)) => Boolean 

How to define function f in order to satisfy the required type of function? I tried adding extra parentheses around (x: Int, y: Int) , but this gave:

 error: not a legal formal parameter val f = ((x: Int, y: Int)) => x > 3 ^ 
+4
source share
3 answers

f is of type Function2[Int, Int, Boolean] . L type IndexedSeq[Tuple2[Int, Int]] , and therefore filter expects a function of type Function1[Tuple2[Int, Int], Boolean] . Each FunctionN[A, B, .., R] tupled has a tupled method that returns a function of type Function1[TupleN[A, B, ..], R] . You can use it here to convert f to the type expected by L.filter .

 println(L.filter(f.tupled)) > Vector((4,16), (5,25)) 

Alternatively, you can redefine f as Function1[Tuple2[Int, Int], Boolean] as follows and use it directly.

 val f = (t: (Int, Int)) => t._1 > 3 println(L.filter(f)) > Vector((4,16), (5,25)) 
+13
source
 val f = (xy: (Int, Int)) => xy._1 > 3 println (L.filter (f)) 

If you do

 val f = (x: Int, y: Int) => x > 3 

you define a function that takes two ints, which is not the same as a function that takes a pair of int parameters as a parameter.

For comparison:

 scala> val f = (x: Int, y: Int) => x > 3 f: (Int, Int) => Boolean = <function2> scala> val f = (xy: (Int, Int)) => xy._1 > 3 f: ((Int, Int)) => Boolean = <function1> 
+6
source

If you do not want to rewrite your function to use Tuple2 explicitly (as suggested by the missing factor and an unknown user), you can define an implicit method to do this automatically. This allows the function f to be untouched (you are not forced to always call it using the Tuple2 parameter) and is easier to understand because you still use the identifiers x and y.

 implicit def fun2ToTuple[A,B,Res](f:(A,B)=>Res):((A,B))=>Res = (t:(A,B)) => f(t._1, t._2) val L = for (x <- (1 to 5)) yield (x, x * x) val f = (x: Int, y: Int) => x > 3 val g = (x: Int, y: Int) => x % 2 > y % 3 L.filter(f) //> Vector((4,16), (5,25)) L.filter(g) //> Vector((3,9)) f(0,1) //> false f((4,2)) //> true 

Now each Function2 can also be used as function 1 with the Tuple2 as parameter, because it uses an implicit method to transform the function, if necessary.

For functions with more than two parameters, implicit defs look similar:

 implicit def fun3ToTuple[A,B,C,Res](f:(A,B,C)=>Res):((A,B,C))=>Res = (t:(A,B,C)) => f(t._1, t._2, t._3) implicit def fun4ToTuple[A,B,C,D,Res](f:(A,B,C,D)=>Res):((A,B,C,D))=>Res = (t:(A,B,C,D)) => f(t._1, t._2, t._3, t._4) ... 
0
source

Source: https://habr.com/ru/post/1381307/


All Articles