I am doing programming in scala for looping through map.
Below is my code which works fine.
val names = Map("fname" -> "Robert", "lname" -> "Goren")
for((k,v) <- names ) println(s"Key: $k, Value : $v")
When looping through the map, if I give (K,V) instead of (k,v), the program is not compiling. It gives cannot resolve symbol error.
Below is my for loop -
for((K,V) <- names ) println(s"Key: $K, Value : $V")
I am executing this program in IntelliJ IDEA 15 scala worksheet.
Can anyone please explain the reason for this error.
It doesn't compile for the same reason this code doesn't compile:
val (A,B) = (1,2)
// error: not found: value A
// error: not found: value B
but this does compile:
val (a,b) = (1,2)
// a: Int = 1
// b: Int = 2
Constant names should be in upper camel case. That is, if the member
is final, immutable and it belongs to a package object or an object,
it may be considered a constant
Method, Value and variable names should be in lower camel case
Source: http://docs.scala-lang.org/style/naming-conventions.html
Related
I had defined a val variable (t), and an array(m) with Int values and then tried to perform sum of all elements of array using for loop in two ways:
case1. Using += (Error message: value += is not a member of Int )
case2. Using a=x+y way (Error message: reassignment to val )
Error is expected in this case as I'm trying to re-assign a new value to a val variable but why there is different error message in case1 and case2?
scala> val t = 0
t: Int = 0
scala> val m = Array(1,2,3,4,5,6,7)
n: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7)
case1:
scala> for(e<-m) t+=e
<console>:28: error: value += is not a member of Int
for(e<-m) t+=e
^
case2:
scala> for(e<-m) t=t+e
<console>:28: error: reassignment to val
for(e<-m) t=t+e
^
Consider the desugared version of t += 42 when t is a val:
t.$plus$eq(42)
Note how there is no assignment happening, instead, it is simply a method call on t. Contrast this with desugared version of t += 42 when t is a var and it does not have += method available
t = t.$plus(42)
Here we see an assignment statement. Therefore, as there is no assignment happening in the case of t+=e where t is a val, the error message does not indicate reassignment to val, instead it is complaining about missing method +=, that is, $plus$eq, on t.
All maps in this code are mutable maps due to the import statement earlier on in the full code. The nGramGetter.getNGrams(...) method call returns a Map[String, Int].
def train(files: Array[java.io.File]): Map[Char, Map[Int, Double]] = {
val scores = Map[Char, Map[Int, Double]]().withDefault( x => Map[Int, Double]().withDefaultValue(0.0))
for{
i <- 1 to 4
nGram <- nGramGetter.getNGrams(files, i).filter( x => (x._1.size == 1 || x._2 > 4) && !hasUnwantedChar(x._1) )
char <- nGram._1
} scores(char)(i) += nGram._2
println(scores.size)
val nonUnigramTotals = scores.mapValues( x => x.values.reduce(_+_)-x(1) )
val unigramTotals = scores.mapValues( x => x(1) )
scores.map( x => x._1 -> x._2.map( y => y._1 -> (if(y._1 > 1) y._2/unigramTotals(x._1) else (y._2-nonUnigramTotals(x._1))/unigramTotals(x._1)) ) )
}
I have replaced the scores(char)(i) += nGram._2 line with a few print statements (printing the keys, values and individual chars in each key) to check the output, and the method call is NOT returning an empty list. The line that prints the size of scores, however, is printing a zero. I am almost sure I have used exactly this method to populate a frequency map before, but this time, the map always comes out empty. I have changed withDefault to withDefaultValue and passed in the result of the current function literal as the argument. I have tried both withDefault and withDefaultValue with Map[Int, Double](1->0.0,2->0.0,3->0.0,4->0.0). I am a bit of a Scala noob, so maybe I just don't understand something about the language that is causing the problem. Any idea what's wrong?
The methods withDefault and withDefaultValue do not change the map. Instead, they simply return a default value. Let's remove the syntactic sugar form your statement to see where it goes wrong:
scores(char)(i) += nGram._2
scores(char)(i) = scores(char)(i) + nGram._2
scores.apply(char)(i) = scores.apply(char)(i) + nGram._2
scores.apply(char).update(i, scores.apply(char).apply(i) + nGram._2)
Now, since scores.apply(char) does not exist, a default is being returned, Map[Int, Double]().withDefaultValue(0.0), and that map gets modified. Unfortunately, it never gets assigned to scores, because no update method is called on it. Try this code below -- it's untested, but it shouldn't be hard to get it to work:
scores(char) = scores(char) // initializes the map for that key, if it doesn't exist
scores(char)(i) += nGram._2
If I create a map:
val m = Map((4, 3))
And try to add a new key value pair:
val m_prime = m + (1, 5)
I get:
error: type mismatch;
found : Int(1)
required: (Int, ?)
val m_prime = m + (1, 5)
If I do:
val m_prime = m + ((1, 5))
Or:
val m_prime = m + (1 -> 5)
Then it works. Why doesn't the compiler accept the first example?
I am using 2.10.2
This is indeed very annoying (I run into this frequently). First of all, the + method comes from a general collection trait, taking only one argument—the collection's element type. Map's element type is the pair (A, B). However, Scala interprets the parentheses here as method call parentheses, not a tuple constructor. The explanation is shown in the next section.
To solve this, you can either avoid tuple syntax and use the arrow association key -> value instead, or use double parentheses, or use method updated which is specific to Map. updated does the same as + but takes key and value as separate arguments:
val m_prime = m updated (1, 5)
Still it is unclear why Scala fails here, as in general infix syntax should work and not expect parentheses. It appears that this particular case is broken because of a method overloading: There is a second + method that takes a variable number of tuple arguments.
Demonstration:
trait Foo {
def +(tup: (Int, Int)): Foo
}
def test1(f: Foo) = f + (1, 2) // yes, it works!
trait Baz extends Foo {
def +(tups: (Int, Int)*): Foo // overloaded
}
def test2(b: Baz) = b + (1, 2) // boom. we broke it.
My interpretation is that with the vararg version added, there is now an ambiguity: Is (a, b) a Tuple2 or a list of two arguments a and b (even if a and b are not of type Tuple2, perhaps the compiler would start looking for an implicit conversion). The only way to resolve the ambiguity is to use either of the three approaches described above.
In Scala 2.9.1, when I declare the package object for "com.sample.website"
com.sample
package object website {
val (CONST_1, CONST_2, CONST_3) = (1, 2, 3)
}
The compiler throws 3 errors like
not found: value CONST_1
Am I doing something wrong or am I simply not allowed to use pattern matching value declaration in package objects?
Check this linke How to pattern match into an uppercase variable?, pattern match doesn't work with uppercase variables.
You need to convert it lower case variables or do it seperate.
Pattern matching only binds to lower case variables, in all contexts.
val (A,B) = (1,2) // Checks that A==1 and B==2
val (a,b) = (1,2) // Sets a=1, b=2
I have just noticed that whilst I need clarifying parens when adding a pair to a map, I don't need them when doing a re-assignment:
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) Server VM, Java 1.6.0_18).
Type in expressions to have them evaluated.
Type :help for more information.
Get me some values
scala> var n = Map.empty[Int, String]
n: scala.collection.immutable.Map[Int,String] = Map()
Trying to add to the map with no clarifying parentheses:
scala> n + 1 -> ""
<console>:30: error: type mismatch;
found : Int(1)
required: (Int, ?)
n + 1 -> ""
^
Fails as I expected it to. But doing the same via a re-assignment does not:
scala> n += 1 -> ""
scala> n
res12: scala.collection.immutable.Map[Int,String] = Map(1 -> "")
What is going on? Why is this not failing? Is scalac adding parens itself?
It's just a precedence issue. + and - have the same precedence. = is lower. So Scala sees (n + 1) -> "" in the former case, and n += (1 -> "") in the latter (which is then transformed to n = (n + (1 -> "")) according to the normal rules for assignment operators.
According to scala reference (6.12.4):
Assignment operators are treated specially in that they can be expanded to assignments if no other interpretation is valid. ... The
re-interpretation occurs if the following two conditions are fulfilled.
1. The left-hand-side l does not have a member named +=, and also cannot be converted by an implicit conversion (§6.26) to a value with a member named > +=.
2. The assignment l = l + r is type-correct. In particular this implies that l refers to a variable or object that can be assigned to, and that is convertible to a value with a member named +.
(1) Immutable Map has no member named += (mutable has) and AFAIK, has no implicit conversions to something with that and assignment is definitely type correct (2): n defined as a variable and has member +.