What am I doing wrong? Where does String come from?
Scala code runner version 2.9.2 -- Copyright 2002-2011, LAMP/EPFL
scala> List(1).fold(Map()) { (m, x) => m + (x -> 1) }
<console>:9: error: type mismatch;
found : (Any, Int)
required: String
List(1).fold(Map()) { (m, x) => m + (x -> 1) }
^
scala> List(1).foldLeft(Map()) { (m, x) => m + (x -> 1) }
<console>:9: error: type mismatch;
found : (Int, Int)
required: (Nothing, Nothing)
List(1).foldLeft(Map()) { (m, x) => m + (x -> 1) }
^
I'll answer in reverse order:
With the second error, your need to help type inference: the Scala compiler cannot know the type of Map() (it would need to look forward to the second parameter group, the operator, which it cannot do), so it infers it as Map[Nothing, Nothing](). And then trying to add an (Int, Int) to a Map[Nothing, Nothing] obviously won't work.
With the first error, you use fold, which requires a binary operator, with type (A,A) => A, so in your case probably (Int, Int) => Int, which isn't what you are looking for since your try to fold into a completely different type: foldLeft and foldRight can do that, however.
Edit: it is looking for a String because it believes that m and x have to share the same type, so they have type Any (their only common supertype), which doesn't have a + method, but it has an implicit conversion that provides it for... String concatenation ; so it converts m to a String and then looks for another String on the other side of +. I know, this is sad.
You just need to annotate the types on Map:
scala> List(1).foldLeft(Map[Int, Int]()) { (m, x) => m + (x -> 1) }
res8: scala.collection.immutable.Map[Int,Int] = Map(1 -> 1)
Or, to show the intent in a clearer way:
scala> List(1).foldLeft(Map.empty[Int, Int]) { (m, x) => m + (x -> 1) }
Related
I have the following code snippet which can not be compiled:
val cids = List(1, 2, 3, 4)
val b = Map.newBuilder[Int, Int]
for (c <- cids) {
b += (c, c*2)
}
b.result()
Compiler reports that
console>:11: error: type mismatch;
found : Int
required: (Int, Int)
b += (c, c*2)
I have no idea what's the mistake.
This would work:
for (c <- cids) {
b += ((c, c*2))
}
The parenthesis are parsed by compiler as the argument-list parenthesis of the += function, and not as a tuple. Adding nested parenthesis means a tuple is passed as the argument. It is confusing...
You can fix it the following way:
b += (c->c*2)
This is a duplicate question.
Normally, supplying an untupled arg list works as shown, but it doesn't work when the method is overloaded, because it will choose the method you didn't intend, and not bother to try auto-tupling your args.
scala> class C[A] { def f(a: A) = 42 }
defined class C
scala> val c = new C[(String, Int)]
c: C[(String, Int)] = C#3a022576
scala> c.f("1", 1)
res0: Int = 42
scala> class C[A] { def f(a: A) = 42 ; def f(a: A, b: A, rest: A*) = 17 }
defined class C
scala> val c = new C[(String, Int)]
c: C[(String, Int)] = C#f9cab00
scala> c.f("1", 1)
<console>:14: error: type mismatch;
found : String("1")
required: (String, Int)
c.f("1", 1)
^
An approach using (immutable) values,
(cids zip cids.map(_ * 2)).toMap
Using zip we pair each value with its double, and the resulting list is converted to a Map.
If you go to the documentation you will find : this
The supported API is ms += (k -> v) . That is you need to use
for (c <- cids) {
b += (c -> c*2)
}
Alternately you could use the ((c, c*2)) syntax as suggested above. This is happening because the compiler has no way of knowing that the parentheses are for the tuple. It simply understands that argument as two parameters being passed to the += method.
If I do:
val l = Seq(("un", ""), ("deux", "hehe"), ("trois", "lol"))
l map { t => t._1 + t._2 }
It's ok.
If I do:
val l = Seq(("un", ""), ("deux", "hehe"), ("trois", "lol"))
l map { case (b, n) => b + n }
It's ok too.
But if I do:
val l = Seq(("un", ""), ("deux", "hehe"), ("trois", "lol"))
l map { (b, n) => b + n }
It will not work.
Why should I use "case" keyword to use named tuples?
The error message with 2.11 is more explanatory:
scala> l map { (b, n) => b + n }
<console>:9: error: missing parameter type
Note: The expected type requires a one-argument function accepting a 2-Tuple.
Consider a pattern matching anonymous function, `{ case (b, n) => ... }`
l map { (b, n) => b + n }
^
<console>:9: error: missing parameter type
l map { (b, n) => b + n }
^
For an apply, you get "auto-tupling":
scala> def f(p: (Int, Int)) = p._1 + p._2
f: (p: (Int, Int))Int
scala> f(1,2)
res0: Int = 3
where you supplied two args instead of one.
But you don't get auto-untupling.
People have always wanted it to work that way.
This situation can be understand with the types of inner function.
First, the type syntax of parameter function for the map function is as follows.
Tuple2[Int,Int] => B //Function1[Tuple2[Int, Int], B]
The first parameter function is expand to this.
(t:(Int,Int)) => t._1 + t._2 // type : Tuple2[Int,Int] => Int
This is ok. Then the second function.
(t:(Int, Int)) => t match {
case (a:Int, b:Int) => a + b
}
This is also ok. In the failure scenario,
(a:Int, b:Int) => a + b
Lets check the types of the function
(Int, Int) => Int // Function2[Int, Int, Int]
So the parameter function type is wrong.
As a solution, you can convert multiple arity functions to tuple mode and backward with the helper functions in Function object. You can do following.
val l = Seq(("un", ""), ("deux", "hehe"), ("trois", "lol"))
l map(Function.tupled((b, n) => b + n ))
Please refer Function API for further information.
The type of a function argument passed to map function applied to a sequence is inferred by the type of elements in the sequence. In particular,
scenario 1: l map { t => t._1 + t._2 } is same as l map { t: ((String, String)): (String) => t._1 + t._2 } but shorter, which is possible because of type inference. Scala compiler automatically inferred the type of the argument to be (String, String) => String
scenario 2: you can also write in longer form
l map { t => t match {
case(b, n) => b + n
}
}
scenario 3: a function of wrong type is passed to map, which is similar to
def f1 (a: String, b: String) = a + b
def f2 (t: (String, String)) = t match { case (a, b) => a + b }
l map f1 // won't work
l map f2
Using the solution here, I'm adding two maps together and treating them as if they were sparse vectors. So
def addTwoVectors(map1: Map[Int, Double], map2: Map[Int, Double]) = {
map1 ++ map2.map{ case (k,v) => k -> (v + map1.getOrElse(k,0)) }
}
Now I'd like to make this generic so that
def addTwoMaps[I, D <% Numeric[D]](m1: Map[I, D], m2: Map[I, D]) = {
m1 ++ m2.map{ case (k,v) => k -> (v + m1.getOrElse(k, 0.asInstanceOf[D])) }
}
Unfortunately, it doesn't seem to work:
error: type mismatch;
found : D
required: String
So how do I make this function generic?
How about this one?
import scala.math.Numeric.Implicits._
def addTwoMaps[I, D](m1: Map[I, D], m2: Map[I, D])(implicit numeric: scala.math.Numeric[D]) = {
m1 ++ m2.map{ case (k: I,v: D) => k -> (v + m1.getOrElse(k, numeric.zero)) }
}
Cause I don't know which one Numeric I have, I'm taking this info implicitly, and then importing zero method, which is specific for every Numeric type.
Actually, I do believe, that scalaz solution will be much more cleaner and hope that somebody will post it.
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!
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)
try:
val ys = List((1,2),(3,4),(5,6))
ys map (t => t._1 + t._2)
Can someone please give an example of how to use the HashMap forall() method? I find the Scala docs to be impenetrable.
What I want is something like this:
val myMap = HashMap[Int, Int](1 -> 10, 2 -> 20)
val areAllValuesTenTimesTheKey = myMap.forall((k, v) => k * 10 == v)
but this gives:
error: wrong number of parameters; expected = 1
You need instead
val myMap = HashMap[Int, Int](1 -> 10, 2 -> 20)
val areAllValuesTenTimesTheKey = myMap.forall { case (k, v) => k * 10 == v }
The problem is that forall wants a function that takes a single Tuple2, rather than two arguments. (We're thinking of a Map[A,B] as an Iterable[(A,B)] when we use forall.) Using a case statement is a nice workaround; it's really using pattern matching here to break apart the Tuple2 and give the parts names.
If you don't want to use pattern matching, you could have also written
val areAllValuesTenTimesTheKey = myMap.forall(p => p._1 * 10 == p._2 }
but I think that's less helpful.
forall is passed a single (Int, Int) Tuple (as opposed to multiple parameters). Consider this (which explicitly shows a single tuple value is decomposed):
val areAllValuesTenTimesTheKey = myMap.forall(t => t match { case (k, v) => k * 10 == v })
Or, the short-hand (which actually passes a PartialFunction):
val areAllValuesTenTimesTheKey = myMap.forall {case (k, v) => k * 10 == v}
(These both decompose the tuple take in.)
Additionally, the function can be "tupled"ed:
val myMap = Map((1,10), (2,20))
val fn = (k: Int, v: Int) => k * 10 == v
val tupled_fn = fn.tupled
val areAllValuesTenTimesTheKey = myMap.forall(tupled_fn)
myMap: scala.collection.immutable.Map[Int,Int] = Map((1,10), (2,20))
fn: (Int, Int) => Boolean = // takes in two parameters
tupled_fn: ((Int, Int)) => Boolean = // note that it now takes in a single Tuple
areAllValuesTenTimesTheKey: Boolean = true
Happy coding.
The problem with your code, is that you give forall method a function, that accepts 2 arguments and returns Boolean, or in other words (Int, Int) => Boolean. If you will look in the documentation, then you will find this signature:
def forall (p: ((A, B)) => Boolean): Boolean
in this case forall method expects Tuple2[A, B] => Boolean, so it also can be written like this:
def forall (p: Tuple2[A, B] => Boolean): Boolean
In order to fix your example you can either call forall and give it function, that accepts 1 tuple argument:
myMap.forall(keyVal => keyVal._1 * 10 == keyVal._2)
or you make patterns match and extract key and value:
myMap.forall {case (k, v) => k * 10 == v}
In this case you are giving PartialFunction[(Int, Int), Boolean] to the forall method