Jack Koenig
Jack Koenig

Reputation: 6065

Using collection.Map in foldleft

Can you use collection.Map as the accumulator/return value of a fold?

For example:

Seq(1, 2, 3).foldLeft(collection.Map.empty[Int, Int]) { 
  case (map, i) => map.asInstanceOf[collection.Map[Int, Int]] + (i -> i)
}

Scala gives me the following type error:

 found   : scala.collection.Map[Int,Int]
 required: scala.collection.immutable.Map[Int,Int]
              Seq(1, 2, 3).foldLeft(collection.Map.empty[Int, Int]) { case (map, i) => map.asInstanceOf[collection.Map[Int, Int]] + (i -> i) }

Why is it enforcing use of collection.immutable.Map instead of collection.Map?

EDIT: The pointless casting is a bit misleading so I want to make my intent more clear. I am specifically using collection.Map inside of the fold because it is the superclass of immutable.Map and mutable.Map. In reality, I am using a function inside of the fold that returns collection.Map, consider:

scala> def func(map: collection.Map[Int, Int]): collection.Map[Int, Int] = map
func: (map: scala.collection.Map[Int,Int])scala.collection.Map[Int,Int]

scala> Seq(1, 2, 3).foldLeft(collection.Map.empty[Int, Int])((map, i) => map + (i -> i))
res11: scala.collection.immutable.Map[Int,Int] = Map(1 -> 1, 2 -> 2, 3 -> 3)

scala> Seq(1, 2, 3).foldLeft(collection.Map.empty[Int, Int])((map, i) => func(map) + (i -> i))
<console>:9: error: type mismatch;
 found   : scala.collection.Map[Int,Int]
 required: scala.collection.immutable.Map[Int,Int]
              Seq(1, 2, 3).foldLeft(collection.Map.empty[Int, Int])((map, i) => func(map) + (i -> i))
                                                                                          ^

An answer given below does work: changing the start value from collection.Map.empty[Int, Int] to collection.Map[Int, Int](). I'm not sure why this makes a difference though:

scala> Seq(1, 2, 3).foldLeft(collection.Map[Int, Int]())((map, i) => func(map) + (i -> i))
res13: scala.collection.Map[Int,Int] = Map(1 -> 1, 2 -> 2, 3 -> 3)

Upvotes: 2

Views: 1500

Answers (2)

developer_hatch
developer_hatch

Reputation: 16224

Edit

The method empty returns this:

def empty[A, B]: immutable.Map[A, B] = immutable.Map.empty

That's why you have the error type, so, creating an object with (), will return to you the correct type, collection.Map[Int, Int]:

def func(map: collection.Map[Int, Int]): collection.Map[Int, Int] = map

Seq(1, 2, 3).foldLeft(collection.Map[Int, Int]())((res, i) =>
  res + (i -> i)
) 

Map(1 -> 1, 2 -> 2, 3 -> 3)

Upvotes: 1

sheunis
sheunis

Reputation: 1544

You don't have to cast it, since you've already defined the type:

Seq(1, 2, 3).foldLeft(collection.Map[Int, Int]()) {
  case (map, i) => map + (i -> i)
}

Upvotes: 3

Related Questions