Scala - error when passing parameters - scala

I am doing the Martin Odersky course about Scala.
In one of the assignments I have the following type:
type Occurrences = List[(Char, Int)]
I have defined a method which subtracts an element of type (Char, Int) from an element of type Occurrences.
def subtractOne(x: Occurrences, (char: Char, nr: Int)): Occurrences = x match {
case List() => throw new Exception("can not subtract")
case (char, nr2) :: ocs => {
if(nr2 > nr) (char, nr2 - nr) :: ocs
else if(nr2 == nr) ocs
else throw new Exception("can not subtract")
}
case _ :: ocs => subtractOne(ocs, (char, nr))
}
However, I am getting some unclear errors on the first line: Wrong parameter and Definition or declaration expected.
Is there anything wrong with the way I declared the parameters?

Do not use brackets in parameter list. Unless you want to define tuple but it should be done with one name.
def subtractOne(x: Occurrences, char: Char, nr: Int): Occurrences = x match {

Tuples are defined under one name - charAndNr: (Char, Int)
Also Nil is preferred to List()

Related

Strange Scala 'Type mismatch' error for tuples

I have a function map which takes a Parser and a function defined as follows:
def map[T1, T2](parser: Parser[T1], func: T1 => T2): Parser[T2]
I've created a Parser object of type [(Char, Char)] and a function (Char, Char) => String.
val parser[(Char,Char)] = //...
val asString: (Char, Char) => String = (a: Char, b: Char) => a.toString + b.toString
And then I pass these two to the map function.
val mParser: Parser[String] = map(parser, asString)
I expect everything to work fine but I get a type mismatch error for asString argument saying
Error:(26, 41) type mismatch;
found : (Char, Char) => String
required: ((Char, Char)) => String
map[(Char, Char), String](parser, asString)
I have tried to explicitly specify the types for map as map[(Char, Char), String](parser, asString) but that didn't help either.
The type T1 here is the char tuple (Char, Char) and T2 is a String. So, the function (Char, Char) => String is what's supposed to be the input but scala is expecting a different type.
What am I missing here? Why is it expecting ((Char, Char)) => String instead of (Char,Char) => String?
I'm using Scala 2.12. Don't know if that is relevant in any way.
Your help is appreciated.
The type (Char, Char) => String corresponds to a function that takes two Char parameters and returns a String.
What you want is a function that takes a Tuple2 and returns a String which is somehow different.
Its type should be Tuple2[Char, Char] => String.
Tuple2[Char, Char] corresponds to the type shorthand (Char, Char) but I guess during function definition the compiler interprets the parentheses as if they are used to group the function parameters.
This is a known issue and it's being addressed in scala3.
https://dotty.epfl.ch/docs/reference/auto-parameter-tupling.html
As others pointed out, defining a function, that accepts a Tuple2 rather than two parameters, gets a little tricky, and ugly-looking.
A nice way around that is to use .tupled:
val asString: (Char, Char) => String = (a: Char, b: Char) => a.toString + b.toString
val mParser: Parser[String] = map(parser, asString.tupled)
FunctionN.tupled converts a function accepting N arguments into an equivalent one taking a TupleN.
This is a bit nicer than defining a tuple-taking function, because of the parenthesis quirks you ran into, and also, because you don't have to deconstruct the tuple in the body.

Getting an error "constructor cannot be instantiated to expected type; found : (T1, T2) required: List[(Char, Int)]"

I am new to Scala and working on a small assignment on Lists and Pattern Matching. The assignment is straight forward calculate the frequency of each unique character in a list and emit out a list of (Char,Int) tuples. I am getting the error on the line where I am trying to pattern match (...case(cs.head, _)...) to see if the current character has already been counted.
def times(chars: List[Char]): List[(Char, Int)] = {
def calcCharFreq(c: Char, cs: List[Char], count: Int): (Char, Int) = {
if(cs.isEmpty) (c, count)
else
if(c == cs.head) calcCharFreq(c, cs.tail, count+1)
else calcCharFreq(c, cs.tail, count)
}
def calcFreq(cs: List[Char], pairs: List[(Char, Int)]): List[(Char, Int)] = {
if(cs.isEmpty) pairs
else{
pairs match {
case (cs.head, _) => calcFreq(cs.tail, pairs)
}
calcFreq(cs.tail, calcCharFreq(cs.head, cs.tail, 0) :: pairs)
}
}
calcFreq(chars, Nil)
}
Thanks in advance
SK
To actually check to see if you already have a tuple in pairs that matches your current char (cs.head), you want to replace the else clause containing the match in question with something like:
if (pairs.exists(_._1 == cs.head)) {
calcFreq(cs.tail, pairs)
} else {
calcFreq(cs.tail, calcCharFreq(cs.head, cs.tail, 1) :: pairs) // I noticed this needed to pass a 1, not a 0, for the initial count, or you would fail to count the first instance of the character...
}
The match itself won't compile anyway, for the reasons given already by #tuxdna and #AlexeyRomanov.
You can't use cs.head in pattern matching like this. You need to assign it to a variable starting with a capital letter (lower-case variables in case create a new variable even if there is such an identifier in outer scope).
(_, _) is a pattern for (2-element) tuples, and pairs isn't a tuple. To match a list's head and tail, you write case head :: tail.
Combining, in this case you need
else {
val C = cs.head
pairs match { case C :: _ => ... }
}
Note that you need to handle other cases as well.

Conditions based on type of a variable in scala

I want to handle my if condition based on the type of a variable which is predefined to be Any type and later it got updated to a type either String, Int, double, List or Map
if (type(x)==int){.....}
else if (type(x)==Map){....}
and so on
Is there a function to get the type of a variable or how can i get the type of a variable
to use it in if conditions.I know one of the way is to use
x.getClass.getSimpleName
but when the type of x is a Map
it prints Map1 or Map2 for different Maps which i am not sure what 1 and 2 denotes here
so i cant use it in the if condition since
if (x.getClass.getSimpleName==Map){....}
will be false as I dont know Map1 or Map2 will come
We call this pattern matching and it's one of the most awesome scala parts:
def foo(x: Any) = x match {
case m: Map[_,_] => println("I'm a map!")
case d: Double => println("I'm a double")
case i: Int => println("I'm an int")
case xs: List[_] => println("I'm a list")
}
Underscores denote any type, i don't care which one

Scala - foldLeft type inference fail

In my code, I have the following:
type Occurrences = List[(Char, Int)]
def subtract(x: Occurrences, y: Occurrences): Occurrences = {
val yMap = y.toMap
x foldLeft (List[(Char, Int)]()) { // ERROR
case (a: List[(Char, Int)], xe: (Char, Int)) =>
if(yMap.contains(xe._1)) (xe._1 -> (xe._2 - yMap(xe._1))) :: a
else a
}
}
It fails on compile-time, at the { that is right before the error mark in the code. The error message is the following:
missing parameter type for expanded function The argument types of an
anonymous function must be fully known. (SLS 8.5) Expected type was:
Int
1) How could that be? As far as I can see, there is no room for misinterpretation of type information here, and I find a lot of such examples over the internet. How can I fix that?
2) Why is it thinking that the expected type is Int after all?
The error occurs because you wrote xs foldLeft (init) (f) instead of (xs foldLeft init)(f) or xs.foldLeft(init)(f).
The former does not work, because Scalas operator notation rules allow only to leave the dot and parentheses if a call occurs in form obj method param, which is not the case with foldLeft because it has two parameter lists.

scala: type mismatch error - found T, required String

I'm learning scala, and this question may be stupid, but... why?
For example, this is ok:
def matchList(ls: List[Int]): List[Int] = ls match {
case 1 :: rest => rest
case a :: b :: rest => (a + b) :: rest
case _ => ls
}
matchList: (ls: List[Int])List[Int]
But function with type parameter does not compile:
def matchList[T](ls: List[T]): List[T] = ls match {
case 1 :: rest => rest
case a :: b :: rest => (a + b) :: rest
case _ => ls
}
<console>:10: error: type mismatch;
found : T
required: String
case a :: b :: rest => (a + b) :: rest
Why?
For any type T the operation T + T doesn't make any sense. (Do all types support +? No. Think of adding two dogs or two employees.)
In your case, the string concatenation operator is getting invoked (added via any2stringadd pimp), whose return type is (obviously) String. Hence the error message.
What you need is a way to specify that type T must support an operation where you combine two values of type T to yield a new value of type T. Scalaz's Semigroup fits the bill perfectly.
The following works:
def matchList[T : Semigroup](ls: List[T]): List[T] = ls match {
case 1 :: rest => rest
case a :: b :: rest => (a |+| b) :: rest // |+| is a generic 'combining' operator
case _ => ls
}
I think the problem lies in (a + b), the only universal usage of the + operator is string concatenation, so a and b must both be Strings (or automatically convertible to Strings) in order for that to be valid. Your parameterized type T isn't known to be a String, so it fails to compile.
In the second example, your a, b variables of declared type T are not convertible to String, which is the required argument type of +, inferred from your program (i.e. the view applied to the type of arguments of +in the absence of any other information).
In the first example, inference can guess the right + function to apply, considering it takes as arguments the type of elements of the list, and that thankfully, you have mentioned in the type declaration that the type of those elements is Int. Try typing
"1"+2
1 + 2
... in an REPL and see what Scala tries to do. Then read about views.
Now, I surmise that by using that type parameter T above, you are trying to write a function that works with any numerical type, aren't you ? In that case, you can work with the Numeric trait. I'll let you read up on implicits before suggesting the following:
def matchList[T](ls: List[T])(implicit n:Numeric[T]): List[T] = {
import n.mkNumericOps
ls match {
case 1 :: rest => rest
case a :: b :: rest => (a + b) :: rest
case _ => ls
}}
You get:
matchList(List(1,2,3))
res2: List[Int] = List(2, 3)
matchList(List(2,3,4))
res4: List[Int] = List(5, 4)
matchList(List(2.0,3.0,4.0))
res5: List[Double] = List(5.0, 4.0)
Without any import:
def matchList[T](ls: List[T])(implicit wrapper:Numeric[T]): List[T] = ls match {
case 1 :: rest => rest
case a :: b :: rest => wrapper.plus(a, b) :: rest
case _ => ls
}