Scala: Why foreach with one argument function doesn't work with a wrist-fastened result

I have the following Scala program:

object Test extends App { val zip = (List(1, 3, 5), List(2, 4, 6)).zipped val f: Tuple2[Int, Int] => Unit = x => println(x._1 + x._2) zip.foreach(f) } 

Why am I getting the following compiler error:

 Error:(6, 15) type mismatch; found : ((Int, Int)) => Unit required: (Int, Int) => ? zip.foreach(f) 

when there is an implicit conversion from Tuple2Zipped to Traversable , where foreach[U](f: ((El1, El2)) => U): Unit defined.

NOTE. I changed my question to clarify.

I know that foreach defined in Tuple2Zipped has the following signature:

 def foreach[U](f: (El1, El2) => U): Unit 

and that my function f does not match the argument.

But in Tuple2Zipped.scala, the ZippedTraversable2 trait and its companion object are defined like this:

 trait ZippedTraversable2[+El1, +El2] extends Any { def foreach[U](f: (El1, El2) => U): Unit } object ZippedTraversable2 { implicit def zippedTraversable2ToTraversable[El1, El2](zz: ZippedTraversable2[El1, El2]): Traversable[(El1, El2)] = { new scala.collection.AbstractTraversable[(El1, El2)] { def foreach[U](f: ((El1, El2)) => U): Unit = zz foreach Function.untupled(f) } } } 

since my f function matches the foreach argument defined in Traversable returned by zippedTraversable2ToTraversable , and the companion object defines an implicit conversion from ZippedTraversable2 to this Traversable and Tuple2Zipped is ZippedTraversable2 , I think this conversion needs to be tried and accepted by my function.

The Intellij Idea editor accepts my design without reporting any error, but the compiler does not work with the error shown.

0
source share
4 answers

Thanks to Jasper-M, I knew that a Scala bug was reported about this problem: https://github.com/scala/bug/issues/9523 . This error was reported by Michael Pollmeier , who asked this question a year and a half ago: Why is Scala an implicit permission denial for an overloaded method with a type parameter?

jamborta posted a question with a more general example in the same problem here .

0
source

Here is another and slightly more esoteric way to fix your code.

 zip.foreach(Function.untupled(f)) 

Function.untupled() will take ((Int, Int)) => Unit , which you have in f , and return (Int, Int) => Unit what you need to handle the zip elements.

+1
source

Your function f is incorrect (it is also explicitly indicated in the error)

zip.foreach expects Function2 , which takes type T1 , type T2 and returns R , but you pass Function1 , which takes Tuple2[Int,Int] as type T1

This explains your compilation error:

found : ((Int, Int)) => Unit EQUALS Function1[Tuple2[Int,Int]] => Unit

While

required: (Int, Int) => Unit EQUALS Function2[Int,Int,Unit]

(Keep in mind that () is syntactic sugar for Tuple* , so you see a double bracket)

Here is an example that compiles:

 val zip = (List(1, 3, 5), List(2, 4, 6)).zipped val f:Function2[Int,Int,Unit] = (x,y) => println(x + y) zip.foreach[Unit](f) 
0
source

Your object is runtime.Tuple2Zipped if you look at the signature

 def foreach[U](f: (El1, El2) => U): Unit 

Function f: (El1, E1l2) => U required, but your function f: ((El1, El2)) => U , therefore, an error.

I was also baffled, since Tuple2Zipped almost like List[(A,B)] , in fact, the toList method could do just that:

 val zip = (List(1, 3, 5), List(2, 4, 6)).zipped.toList val f: Tuple2[Int, Int] => Unit = x => println(x._1 + x._2) zip.foreach(f) 

Edit

I think you're looking for an implicit conversion from ((A, B)) => U to (A, B) => U , which is not what zippedTraversable2ToTraversable does. You can define something like this:

 implicit def tupconv[A,B] (f: (((A,B)) => Unit)): (A, B) => Unit = Function.untupled(f) 

Change V2

For the above code, you will need an implicit scope variable that will display from ((A,B)) => Unit to (A, B) => Unit as such where a mismatch exists. While the one you specified executes ZippedTraversable2[El1, El2] to Traversable[(El1, El2)] . If you want to use this implicit conversion, you can do this:

 val zip = (List(1, 3, 5), List(2, 4, 6)).zipped val f: Tuple2[Int, Int] => Unit = x => println(x._1 + x._2) def thisUsesTheImplicitYouWant(t: Traversable[(Int,Int)]) = t.foreach(f) thisUsesTheImplicitYouWant(zip) 
0
source

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


All Articles