Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: Difference in function type inference between reduce and fold - can something be done about it?

Let's say I have an empty map
val map = Map[Int, Int]()

I'm confused because while the following code compiles properly:

map.foldLeft((0,0)){case((k1, v1), (k2, v2)) => (-1, -1)}

the following, seemingly exact code snippet results in compilation error:

map reduceLeft {case((k1, v1), (k2, v2)) => (-1, -1)}

The error is:

scala> map reduceLeft {case((k1, v1), (k2, v2)) => (k1, v1)}
<console>:9: error: missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: (?, (Int, Int)) => ?
              map reduceLeft {case((k1, v1), (k2, v2)) => (k1, v1)}

It's not a huge problem, but obviously it would be nice to not have to deal with this. Do you have any ideas on what could I do differently, or do I just have to learn to accept it?

like image 231
Lukasz Gieron Avatar asked Jan 15 '23 06:01

Lukasz Gieron


1 Answers

The reason this happens is that foldLeft has two parameter lists (the 1st being the initial, "priming" value and 2nd being the function) and reduceLeft has only one (the function).

Scala's type inference operates one parameter list at a time. Additionally, types inferred in one parameter list are available to guide or constrain type inference in later ones (those further right) in ways they cannot help guide or constrain type inference within a given parameter list. In this case, Scala cannot infer properly the B type in the reduceLeft signature:

def reduceLeft[B >: (A, B)](op: (B, (A, B)) ⇒ B): B 

While in the fold case:

def foldLeft[B](z: B)(op: (B, (A, B)) ⇒ B): B

it binds a type to B by looking at your primer value alone ((0, 0)) which it then has available to infer the parameter types in the function (without you making them explicit).

like image 61
Randall Schulz Avatar answered Feb 03 '23 18:02

Randall Schulz