talex
talex

Reputation: 20436

Type of "foreach" in Scala

I have example code:

  def test = {
    val l : Seq[(String, String)] = Seq()
    val foo : (String, String) => Unit = {case (a, b)=>}
    l.foreach[Unit](foo)
  }

It gives me the next error:

Error:(8, 21) type mismatch;
 found   : (String, String) => Unit
 required: ((String, String)) => Unit
    l.foreach[Unit](foo)

As far as I understand foreach has a type (A=>U)=>Unit where:

My question is why is ((String, String)) => Unit required? Where do the extra brackets come from?

Upvotes: 1

Views: 899

Answers (3)

Ihor Kaharlichenko
Ihor Kaharlichenko

Reputation: 6260

Let's start from top.

You have

val l: Seq[(String, String)]

that is a Seq of tuples of two strings. So each of the elements of l is of type (String, String) which is a syntactic sugar for Tuple2[String, String].

Now you have

val foo: (String, String) => Unit

that is a function of two arguments each being String. Again, the type signature above is syntactic sugar for Function2[String, String, Unit].

Considering the above your code can be rewritten as follows:

def test = {
    val l: Seq[Tuple2[String, String]] = Seq()
    val foo: Function2[String, String, Unit] = {case (a, b)=>}
    l.foreach[Unit](foo)
}

foreach expects a single argument function, i.e. a Function1[T, R], thus the type mismatch.

Upvotes: 2

Till Rohrmann
Till Rohrmann

Reputation: 13346

The type definition foo: (String, String) => Unit says that foo is a function which takes two parameters of type String. However, your sequence l: Seq[(String, String)] contains tuples of type type t = (String, String). Thus, calling l.foreach expects a function which is applicable to the tuple type t. Thus, it expects a function of type t => Unit, which is equivalent to ((String, String)) => Unit.

Upvotes: 1

Marth
Marth

Reputation: 24802

If you check in the REPL, you'll see that foo is a <function2>, that is, a function that takes 2 argument:

scala> val foo : (String, String) => Unit = {case (a, b)=>}
foo: (String, String) => Unit = <function2>

.foreach however expects a function that takes a single arguement (of type A), which in your case is a Tuple2.
If you set foo to be a <function1>, then it works:

scala> val foo : ((String, String)) => Unit = {case (a, b)=>}
foo: ((String, String)) => Unit = <function1>

scala> val l : Seq[(String, String)] = Seq()
l: Seq[(String, String)] = List()

scala> l.foreach[Unit](foo)

scala>

Upvotes: 4

Related Questions