Scala - Type Mismatch Found Unit : required Array[Int] - scala

Why does the method give a compile error in NetBeans
( error in question -- Type Mismatch Found Unit : required Array[Int] )
def createArray(n:Int):Array[Int] =
{
var x = new Array[Int](n)
for(i <- 0 to x.length-1)
x(i) = scala.util.Random.nextInt(n)
}
I know that if there was a if clause - and no else clause - then why we get the type mismatch.
However, I am unable to resolve this above error - unless I add this line
return x
The error is not happening because the compiler thinks what happens if n <= 0
I tried writing the function with n = 10 as hardcoded
Thoughts ?

Your for comprehension will be converted into something like:
0.to(x.length - 1).foreach(i => x(i) = scala.util.Random.nextInt(i))
Since foreach returns (), the result of your for comprehension is (), so the result of the entire function is () since it is the last expression.
You need to return the array x instead:
for(i <- 0 to x.length-1)
x(i) = scala.util.Random.nextInt(n)
x

Yet another one,
def createArray(n: Int): Array[Int] = Array.fill(n) { scala.util.Random.nextInt(n) }
Then, for instance
val x: Array[Int] = createArray(10)

You could do something cleaner in my own opinion using yield :
def createArray(n:Int):Array[Int] =
(for(i: Int <- 0 to n-1) yield scala.util.Random.nextInt(n)).toArray
This will make a "one lined function"

Related

Type Mismatch Unit and String in Scala

I am trying to take from a list of tuples (e.g. List[(String, String)]) some words that have the difference between the number of syllables smaller than 2.
If that is ok, I return them - however, I have some issues: I get Unit found and String expected.
def ecrire():String = {
// Choose deux output: List[(Word, Word)]
// I take every tuple of the list and proceed as the element "b"
for (b <- choose_deux()){
val x = b._1
val y = b._2
val diff = Math.abs(x.syllabes - y.syllabes)
// Check if difference between syllables is smaller than 2
if(diff <= 2)
return x.toString() + "\n" + y.toString()
}
}
}
Now I know that probably I have to do a yield at the bottom, but yield what exactly? The idea is that if the condition shown in the "if" is respected, I write the string made of these two elements.
The error is shown at the for loop: type mismatch; found: Unit; required: String
Could you please help me a bit? I am still new and learning!
Type mismatch error is because your for loop doesn't have else statement and you can't return using if inside a for loop. So for loop is not returning anything so scala compiler assumes the return type to be () i.e. unit() and you have defined the return type as String.
Defining the functions in the following way should solve your issue
def diff(x) = Math.abs(x._1.syllabes - x._2.syllabes)
for (b <- choose_deux() if(diff(b) <= 2)) yield b._1.toString() + "\n" + b._2.toString()

Passing a function to another function as statement

I want to write a function which will return true if given an even number as an argument or false otherwise. additionally, write a function that will filter a list of numbers returning just the even numbers. All done using Scala functional programming. This is what I have:
def isEven(n:Int): Boolean = n % 2 == 0
println(isEven(4))
val filterEven = ( xs :List[Int] ) => {
for( x <- xs; if x % 2 == 0 ) yield x
}
println(filterEven(List(3,2,4,5,6,22,91)))
My question is, how can I pass the first function "isEven" to to the "filterEven" function in order to replace the "if-statement"?
Regards.
You can pass isEven as a parameter to xs.filter
def filterEven(xs: List[Int]) = xs.filter(isEven)
This is functionally equivalent to:
def filterEven(xs: List[Int]) = for { x <- xs if isEven(x) } yield x
First you give it a name when it is passed in.
val filterEven = (xs :List[Int], filterFunc: Int => Boolean) => {
Then you invoke it under its new name.
for(x <- xs; if filterFunc(x)) yield x
Note that now filterEven is not a good name for your function. The parameter passed in as filterFunc will determine whether you filter even, or odd, or less than 100, or .....

Identifier expected but integer literal found

I got this problem when writing a recursive function that calculates the number of points where two general functions f1 and f2 are equal(Assuming only Integer values).
object X1 {
def numEqual(f1:Int=>Int,f2:Int=>Int)(a:Int,b:Int):Int=
if(a>b) 0
else f1(a)==f2(a) ? 1+numEqual(f1,f2)(a+1,b):0+numEqual(f1,f2)(a+1,b)
And this is what compiler says :
X1.scala:5: error: identifier expected but integer literal found.
f1(a)==f2(a) ? 1+numEqual(f1,f2)(a+1,b) : 0+numEqual(f1,f2)(a+1,b)
^
one error found.
Thank you!
The if construct in Scala is an expression. As the others already said, there's no ternary operator because there's no need for it - the if being already an expression.
I rewrote your function to a tail-recursive version (to avoid StackOverflowErrors), let's see how it looks:
#tailrec def numEqual(f1: Int => Int, f2: Int => Int)(a: Int, b: Int, res: Int = 0): Int =
if (a > b) res
else {
val inc = if (f1(a) == f2(a)) 1 else 0
numEqual(f1, f2)(a + 1, b, res + inc)
}
Notice how the result of the if expression is assigned to inc - here you would normally use the ternary operator. Anyway, I hope this helps you.
the ? : operator doesn't exist in scala
Scala does not use the ternary operator, http://alvinalexander.com/scala/scala-ternary-operator-syntax

Scala for comprehension of sequence inside a Try

I am writing a Scala program in which there is an operation that creates a sequence. The operation might fail, so I enclose it inside a Try. I want to do sequence creation and enumeration inside a for comprehension, so that a successfully-created sequence yields a sequence of tuples where the first element is the sequence and the second is an element of it.
To simplify the problem, make my sequence a Range of integers and define a createRange function that fails if it is asked to create a range of an odd length. Here is a simple for comprehension that does what I want.
import scala.util.Try
def createRange(n: Int): Try[Range] = {
Try {
if (n % 2 == 1) throw new Exception
else Range(0, n)
}
}
def rangeElements(n: Int) {
for {
r <- createRange(n)
x <- r
} println(s"$r\t$x")
}
def main(args: Array[String]) {
println("Range length 3")
rangeElements(3)
println("Range length 4")
rangeElements(4)
}
If you run this it correctly prints.
Range length 3
Range length 4
Range(0, 1, 2, 3) 0
Range(0, 1, 2, 3) 1
Range(0, 1, 2, 3) 2
Range(0, 1, 2, 3) 3
Now I would like to rewrite my rangeElements function so that instead of printing as a side-effect it returns a sequence of integers, where the sequence is empty if the range was not created. What I want to write is this.
def rangeElements(n: Int):Seq[(Range,Int)] = {
for {
r <- createRange(n)
x <- r
} yield (r, x)
}
// rangeElements(3) returns an empty sequence
// rangeElements(4) returns the sequence (Range(0,1,2,3), 0), (Range(0,1,2,3), 1) etc.
This gives me two type mismatch compiler errors. The r <- createRange(n) line required Seq[Int] but found scala.util.Try[Nothing]. The x <- r line required scala.util.Try[?] but found scala.collection.immutable.IndexedSeq[Int].
Presumably there is some type erasure with the Try that is messing me up, but I can't figure out what it is. I've tried various toOption and toSeq qualifiers on the lines in the for comprehension to no avail.
If I only needed to yield the range elements I could explicitly handle the Success and Failure conditions of createRange myself as suggested by the first two answers below. However, I need access to both the range and its individual elements.
I realize this is a strange-sounding example. The real problem I am trying to solve is a complicated recursive search, but I don't want to add in all its details because that would just confuse the issue here.
How do I write rangeElements to yield the desired sequences?
The problem becomes clear if you translate the for comprehension to its map/flatMap implementation (as described in the Scala Language Spec 6.19). The flatMap has the result type Try[U] but your function expects Seq[Int].
for {
r <- createRange(n)
x <- r
} yield x
createRange(n).flatMap {
case r => r.map {
case x => x
}
}
Is there any reason why you don't use the getOrElse method?
def rangeElements(n: Int):Seq[Int] =
createRange(n) getOrElse Seq.empty
The Try will be Success with a Range when n is even or a Failure with an Exception when n is odd. In rangeElements match and extract those values. Success will contain the valid Range and Failure will contain the Exception. Instead of returning the Exception return an empty Seq.
import scala.util.{Try, Success, Failure}
def createRange(n: Int): Try[Range] = {
Try {
if (n % 2 == 1) throw new Exception
else Range(0, n)
}
}
def rangeElements(n: Int):Seq[Tuple2[Range, Int]] = createRange(n) match {
case Success(s) => s.map(xs => (s, xs))
case Failure(f) => Seq()
}
scala> rangeElements(3)
res35: Seq[(Range, Int)] = List()
scala> rangeElements(4)
res36: Seq[(Range, Int)] = Vector((Range(0, 1, 2, 3),0), (Range(0, 1, 2, 3),1), (Range(0, 1, 2, 3),2), (Range(0, 1, 2,3),3))

Adding to scala map within for loop and conditional statement

I'm getting an error message of "error: type arguments [Any] do not conform to trait Cloneable's type parameter bounds [+A <: AnyRef]," which I can't make heads or tails of.
Specifically,
var M = mutable.Map[Int, mutable.Set[Int]]()
for(i <- 1 to 100; j <- 1 to 100) {
if(!M.contains(i)) {M += i -> mutable.Set[Int](j)}
else {M(i) += j}
}
(I'm actually trying something more complicated, but this is the error generating code tweaked and simplified to a minimum)
And the last line of the above code generates the error message. If I strip it down further
for(i <- 1 to 100; j <- 1 to 100) {
if(!M.contains(i)) {M += i -> mutable.Set[Int](j)}
}
it works!
How do I make the above code work?
Digal diagnosed the problem (failure to unify the types of the if-else branches) and it looks like a compiler bug. Here's a further simplified case that will give an error in the REPL, after a lengthy compilation time,
if (true) {
null: collection.mutable.Map[Int, Int]
} else {
null: collection.mutable.Set[Int]
}
In the meantime, you can get your code to compile with an explicit type sprinkled somewhere in the if-else statement,
for(i <- 1 to 100; j <- 1 to 100) {
if(!M.contains(i)) {M += i -> mutable.Set[Int](j)}
else {M(i) += j}: Unit
}
I filed an issue here: https://issues.scala-lang.org/browse/SI-4938
I've reduced your example even further:
scala> if(!M.contains(1)) {M += 1 -> mutable.Set[Int](1)} else {M(1) += 1};
<console>:9: error: type arguments [Any] do not conform to trait Cloneable's type parameter bounds [+A <: AnyRef]
val res17 =
^
The problem seem to occur when compiler tries to find common return type for both branches:
The first one is
scala> M += 1 -> mutable.Set[Int](1)
res19: scala.collection.mutable.Map[Int,scala.collection.mutable.Set[Int]] = ...
And the "else" part is
scala> M(1) += 1
res18: scala.collection.mutable.Set[Int] = Set(1)
If I add a return value to the end of this expression, REPL eats it without errors:
scala> if(!M.contains(1)) {M += 1 -> mutable.Set[Int](1)} else {M(1) += 1}; println("hello")
hello
Because the expression's return type is Unit.