1

can someone explain the best way to get around the following, rather curious type error. Suppose I create a list of tuples like so:

scala> val ys = List((1,2), (3,4), (5,6))
ys: List[(Int, Int)] = List((1,2), (3,4), (5,6))

Now, if I want to map this to a List(Int)

scala> ys.map((a: Int, b: Int) => a + b)
<console>:9: error: type mismatch;
found   : (Int, Int) => Int
required: ((Int, Int)) => ?
   ys.map((a: Int, b: Int) => a + b)
                           ^

Any clues? I know I can use the for comprehension

scala> for ((a, b) <- ys) yield a + b
res1: List[Int] = List(3, 7, 11)

But it feels wrong to bust out a comprehension in this setting. Thanks!

2 Answers 2

7

try:

ys.map { case (a: Int, b: Int) => a + b }

or:

ys.map(p: (Int, Int) => p._1 + p._2)

What's happening is that ys is a List of (Int,Int), so map expects a function from a single argument, which happens to be a tuple (Int,Int), to something else (technically, map expects an argument of Function1[(Int,Int),Int]. The function (a: Int, b: Int) => a+b is not actually a function from a single argument (Int, Int) to Int; instead it's a function of two arguments, both Ints, to an Int (a Function2[Int,Int,Int]). The difference is subtle, but important since Scala makes a distinction:

val f: Function1[(Int,Int),Int] = (p: (Int,Int)) => p._1 + p._2
ys.map(f) // fine

val g: Function1[(Int,Int),Int] = { case (a: Int, b: Int) => a + b }
ys.map(g) // fine, technically a PartialFunction[(Int,Int),Int]

val h: Function2[Int,Int,Int] = (a: Int, b: Int) => a + b
ys.map(h) // ERROR!

To explain my suggestions at the top of the answer: In the first example, we have changed the definition of the function given to map to use case, which tells Scala to unpack the single (Int,Int) argument into its two parts. (Note also the use of curly braces instead of parentheses.) In the second example, we have a function of a single tuple argument, p, and we manually extract each part of the tuple.

Finally, note that you don't need the type annotations either. These work just as well:

ys.map { case (a,b) => a + b }

ys.map(p => p._1 + p._2)
Sign up to request clarification or add additional context in comments.

2 Comments

It is worth noting that the solution using the "case" statement is supplying a partial function as an argument to map, which is why it is able to unapply the pair right away. And the reason a partial function can be provided instead of a regular function is that partial function extends function.
Sweet, thanks! This makes perfect sense. I got bitten by my ML background ... ;-)
0

try:

  val ys = List((1,2),(3,4),(5,6))
  ys map (t => t._1 + t._2)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.