I have piece of code like this:
sealed trait Json
case class JsonNumber(number: Double) extends Json
case class JsonString(text: String) extends Json
case class JsonObject(obj: Map[String, Json]) extends Json
....and then
def trimAll(json: Json): Json =
json match {
case _: JsonNumber => json
case JsonString(str) => JsonString(str.trim)
case JsonObject(obj) =>
val newObj = obj.map {
case (key, value) => (key, trimAll(value))
}
JsonObject(newObj)
}
Why does obj.map work here? When I see Map.map code, it's as:
def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] = mapFactory.from(new View.Map(toIterable, f))
So it expects a function which takes input tuple (K,V) and returns another tuple. But in code above we are rather having:
{
case (key, value) => (key, trimAll(value))
}
...and more surprisingly, if I do this:
val newObj = obj.map((k, v) => (k, trimAll(v)))
While this matches the signature of Map.map exactly, it gives me error:
Cannot resolve overloaded method 'map'
Edit: error trace is as:
[error] Note: The expected type requires a one-argument function accepting a 2-Tuple.
[error] Consider a pattern matching anonymous function, `{ case (key, value) => ... }`
[error] val newObj = obj.map((key,value) => (key, trimAll(value)))
[error] ^
[error] .../JsonExercises.scala:18:37: missing parameter type
[error] val newObj = obj.map((key,value) => (key, trimAll(value)))
This worked though:
val newObj = obj.map(kv => (kv._1, trimAll(kv._2)))
CodePudding user response:
I am assuming you are using Scala 2, as this was "resolved" in Scala 3.
case
inside a map
allows you to short hand pattern match the arguments, thus allowing you to explode the tuple into two named variables.
Let's take a closer look at the signature of map
def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] = ...
Notice the extra parentheses around (K, V)
so map
expects a unary function (function of one argument) that takes a tuple and returns another tuple.
So when you do
obj.map((k, v) => (k, trimAll(v)))
It is interpreted as a binary function, taking two arguments k
and v
and thus doesn't work.
Now you would think that you would be able to solve this as,
obj.map(((k, v)) => (k, trimAll(v)))
which unfortunately is a syntax that isn't supported in Scala 2. Tuples can not be deconstruction in the parameter in Scala 2.
As a work around, map( case ...))
syntax was developed.
Hope this clarifies it
CodePudding user response:
Short version: (k, v) => (k, trimAll(v))
is a function that takes two arguments, not a function that takes a single tuple argument.