12

Related to Tuple Unpacking in Map Operations, I don't understand why do we need a case (that looks like a partial function to me) to extract values from tuple, like that:

arrayOfTuples map {case (e1, e2) => e1.toString + e2}

Instead of extracting in the same way it works in foldLeft, for example

def sum(list: List[Int]): Int = list.foldLeft(0)((r,c) => r+c)

Anyway we don't specify the type of parameters in the first case, so why do we need the case statement?

Community
  • 1
  • 1
eugen-fried
  • 2,111
  • 3
  • 27
  • 48

2 Answers2

13

Because in Scala function argument lists and tuples are not a unified concept as they are in Haskell and other functional languages. So a function:

(t: (Int, Int)) => ...

is not the same thing as a function:

(e1: Int, e2: Int) => ...

In the first case you can use pattern matching to extract the tuple elements, and that's always done using case syntax. Actually, the expression:

{case (e1, e2) => ...}

is shorthand for:

t => t match {case (e1, e2) => ...}

There has been some discussions about unifying tuples and function argument lists, but there are complications regarding Java overloading rules, and also default/named arguments. So, I think it's unlikely the concepts will ever be unified in Scala.

Jesper Nordenberg
  • 2,104
  • 11
  • 15
  • I don't think this is correct. Even in Haskell, a function f taking two parameters f :: a -> b -> c is different from a function g taking a 2-tuple as its only parameter g :: (a,b) -> c. You translate between these two functions using currying: f = curry g. The advantage of Haskell is, that you can pattern match directly in the parameter declaration. But this works with any type constructor, not only for tuples: h (Just x) = x + 1. With Scala you must invoke pattern matching explicitly (using "match" or "case"). – stefan.schwetschke Dec 17 '14 at 08:37
  • 1
    You're mixing things up. The Haskell function `f :: a -> b -> c` corresponds to the Scala function `f: A => B => C` or method `def f(x: A)(y: B): C`. The Haskell function `g :: (a, b) -> c` corresponds to the Scala function `g: ((A, B)) => C` or method `def g(t: (A, B)): C`. The Scala function `h: (A, B) => C` or method `def h(x: A, y: B): C` cannot be called with one argument and thus has no correspondence in Haskell. But you are correct that Haskell can do pattern matching in parameter lists while Scala cannot. – Jesper Nordenberg Dec 17 '14 at 08:51
  • Dotty (which will eventually become Scala 3) now automatically tuples function parameters. – 6infinity8 Dec 14 '19 at 09:30
5

Lambda with one primitive parameter

With

var listOfInt=(1 to 100).toList
listOfInt.foldRight(0)((current,acc)=>current+acc)

you have a lambda function operating on two parameter.

Lambda with one parameter of type tuple

With

var listOfTuple=List((1,"a"),(2,"b"),(3," "))
listOfTuple.map(x => x._1.toString + x._2.toString)

you have a lambda function working on one parameter (of type Tuple2[Int, String])

Both works fine with type inference.

Partial lambda with one parameter

With

listOfTuple.map{case (x,y) => x.toString + y.toString}

you have a lambda function, working with one parameter (of type Tuple2[Int, String]). This lambda function then uses Tuple2.unapply internally to decompose the one parameter in multiple values. This still works fine with type inference. The case is needed for the decomposition ("pattern matching") of the value.

This example is a little bit unintuitive, because unapply returns a Tuple as its result. In this special case there might indeed be a trick, so Scala uses the provided tuple directly. But I am not really aware of such a trick.

Update: Lambda function with currying

Indeed there is a trick. With

import Function.tupled
listOfTuple map tupled{(x,y) => x.toString + y.toString}

you can directly work with the tuple. But of course this is really a trick: You provide a function operating on two parameters and not with a tuple. tupled then takes that function and changes it to a different function, operating on a tuple. This technique is also called uncurrying.

Remark:

The y.toString is superfluous when y is already a string. This is not considered good style. I leave it in for the sake of the example. You should omit it in real code.

stefan.schwetschke
  • 8,862
  • 1
  • 26
  • 30
  • Regarding the `y.toString` - I just took the first `foldLeft` I could find in google, the ones in our project were way too complicated for an example. – eugen-fried Dec 16 '14 at 11:49
  • Great! I do not understand why `listOfTuple.map{case (x,y) => x.toString + y.toString}` is called partial lambda. It seems to me we have used all parameters. – Jill Clover Mar 02 '18 at 04:16