Block statements in anonymous Scala function - scala

I've created this simple anonymous function
var b = (x : Int) => if(x % 2 == 0) x + 1 else x
and it works great. After that I tried to add another statement after the if and before the x+1 statement.
var b = (x : Int) => if(x % 2 == 0) println(x) x + 1 else x
and a that point I received the following compiler error
Cannot resolve symbol x
Please can anyone let me know why this happen?

The reason this happens is that although Scala does not require the use of semi-colons most of the time (unlike Java), since the compiler is more equipped to infer where statements/expressions end, if you have 2 statements/expressions on 1 line then you need to separate them for the compiler.
Your first anonymous function works since if(x % 2 == 0) x + 1 else x is 1 expression.
The compiler is complaining with the second one though since if(x % 2 == 0) println(x) is considered 1 statement. Hence, the next statement starts and there is now no context for x.
Other posters have given you a solution to break the right-side of the function down into separate statements so I won't duplicate - just adding an explanation of why the compilation error occurs since you said you are learning the language. Google about the use of semi-colons in Scala to find out more.

Use this. You need the braces to indicate these are multiple lines:
var b = (x : Int) => if(x % 2 == 0) {
println(x)
x + 1
} else x
Or you can do this.. you need to put that semi colon to indicate to compiler they are separate statements:
var b = (x : Int) => if(x % 2 == 0) { println(x); x + 1 } else x

Related

How to use placeholder syntax properly with map?

I am trying to use placeholder syntax for simple map:
Array(1,2,3).map(if(_ % 2 == 0) _ * 2)
I was expecting to have the same effect as:
Array(1,2,3).map(i=>if (i%2==0) i * 2)
It complains
error: type mismatch;
found : Unit
required: Int => ?
I also tried:
Array(1,2,3).map(if(_ % 2 == 0) _ * 2 else _) //with else
Array(1,2,3).map(if((_:Int) % 2 == 0) (_:Int) * 2 else (_:Int)) //All typed
Array(1,2,3).map(if((_:Int) % 2 == 0) 0 else 1) //Typed and specific return Int
Every one of them gives error. How to properly use this syntax in this case?
Edit
The link states that filter(_:Boolean) and filter (_ == true) should work, but my trials with specific typing does not work. This link also states that if (_) x else y should work, but in my case it does not. Need more explanation.
Edit 2
Tried:
Array(true,false).map(if(_) 0 else 1)
It works. But my case:
Array(1,2,3).map(if((_) % 2 == 0) 0 else 1)
Does not work.
Does this syntax only support such simple expressions?
Re: your original question:
Array(1, 2, 3).map(if (_ % 2 == 0) _ * 2)
// error: missing parameter type for expanded function ...
// error: type mismatch ...
The _ placeholder used in such pattern represents positional parameters of an anonymous function, hence if (_ % 2 == 0) _ * 2 is equivalent to:
if (x => x % 2 == 0) y => y * 2
That explains the missing parameter error. The type mismatch error is due to missing else in the if statement, forcing the compiler to return a Unit:
Array(1, 2, 3).map(i => if (i % 2 == 0) i * 2 else i)
// res1: Array[Int] = Array(1, 4, 3
Given that you need to specify the single input multiple times I'm not sure it'll work for you.
As you've already noticed, this placeholder syntax does have its limitation and should be treated as a convenient shortform for relatively simple cases. Like the if (_ % 2 == 0) 0 else 1) case, nesting _ within a map generally does not work well. For example:
List("a", "b", "c").map(_ * 3)
// res2: List[String] = List(aaa, bbb, ccc)
List("a", "b", "c").map((_ + " ") * 3)
// error: missing parameter type for expanded function ...
For more usage re: _, here is a SO link, and a Scala doc about commonly used symbols including _.

Scala: AnyVal usage

I am setting a val in Scala using an if statement, I only want to set the val when certain criteria is met and I would like it to be an Int. I use/compare the val later on with another Int which is (currently) always positive:
val transpose = if(x < y) 10 else -1
...
if(transpose > min) doSomething
I do not like this code because, in the future, min may in fact be negative.
I have changed the if statement to:
val transpose = if(x < y) 10
This returns a type AnyVal. I am wondering how I can utilise this? I still wish to compare the value held within the AnyVal with min but only if it is an Int, otherwise, I want to continue as if the if statement was unsuccessful. In pseudo-code:
if(transpose instanceOf(Int) && transpose > min) doSomething
I have toyed with using transpose.getClass but it just seems like the wrong way to do it.
Either use an Option, as suggested by Ende Neu:
val transpose = if(x < y) Some(10) else None
if(transpose.exists(_ > min)) doSomething
Or, just use Int.MinValue:
val transpose = if(x < y) 10 else Int.MinValue
if(transpose > min) doSomething // won't doSometihng for any "min" if x < y
Another good option is to make transpose a function of type Int => Boolean (assuming it's only used for this if statement), thus not needing a type to represent the threshold:
val transpose: Int => Boolean = m => if (x < y) 10 > m else false
if(transpose(min)) doSomething

Do if else statements in Scala always require an else?

I have the following function which works fine:
def power(x: Double, n: Int) : Double = {
if (n > 0 && n % 2 == 0) power(x, n/2) * power(x, n/2)
else if (n > 0 && n % 2 == 1) x * power(x, n-1)
else if (n < 0) 1 / power(x, -n)
else 1
}
If I change it to be:
def power(x: Double, n: Int) : Double = {
if (n > 0 && n % 2 == 0) power(x, n/2) * power(x, n/2)
else if (n > 0 && n % 2 == 1) x * power(x, n-1)
else if (n < 0) 1 / power(x, -n)
else if (n==0 ) 1
}
I.e. change the final else statement to be an else if, then I get the following error trying to call the function:
> <console>:8: error: not found: value power
power(2, 1)
^
I'm guessing this is because there is a possible return type of Unit because the value of n could meet none of the conditions?
In Java "if-else" is a statement. In Scala it is an expression (think of Java's ternary ?:), meaning that it always produces some value. As mentioned by som-snytt in comments, in case of a missing else block the compiler supplies else (), which is of type Unit, which obviously conflicts with the expected type Double in your example.
Some valid examples of missing else are provided in Chris's answer.
No - In general, an if expression does not require an else clause.
Examples:
if (true) println("a")
// prints "a"
if (false) println("a") else if (true) println("b")
// prints "b"
As Nikita Volkov's answer says, though, it is necessary if you need the expression to have some type other than Unit.
Your guess is correct. The method must return a Double, yours would return Unit if non of the "if.." cases match. Actually, when you paste the second definition into the repl, you should get
<console>:11: error: type mismatch;
found : Unit
required: Double

Recursive function is overflowing, why?

The below function is overflowing, and I don't understand why. When run with x as 0, y as 0 and dim as 2, the result should be 6. However, I am getting an error indicating that some Long value in the function (either x or y) is 554 at the time of overflow. This should not be possible as x and y are both bounded by the dim value, which in my test is set to 2.
Here is the code:
def lattice(dim: Long, x: Long, y: Long): Long = {
if (x == dim && y == dim) {
1
}
if (x >= dim) {
lattice(dim,x,y+1L)
}
if (y >= dim) {
lattice(dim,x+1L,y)
}
else {
lattice(dim,x+1L,y) + lattice(dim,x,y+1L)
}
}
You are missing else in two places. This means that your final line runs even when x >= dim, causing x to exceed dim. Try this instead:
if (x == dim && y == dim) {
1
} else if (x >= dim) {
lattice(dim,x,y+1L)
} else if (y >= dim) {
lattice(dim,x+1L,y)
} else {
lattice(dim,x+1L,y) + lattice(dim,x,y+1L)
}
Chris:
Youd function is not tail recursive because in your last statement you have a sum. By chance this sum involves two calls to lattice. However, to be tail recursive your last statament must be a constant (like you did in your first if) or just a call to function itself (such as your 2 else ifs.
I admit that I don't know how to change your function to be tail recursive. Depending of your alghoritm, perhaps it is not possible to do your function tail recursive.
Thanks,
Rafael Afonso

Questions about scala

I am currently learning scala. I am reading Scala for the impatient.
1.)
Guards
Is there a difference?
for (i <- 0 to 10)if (i % 2 == 0) println(i)
for (i <- 0 to 10 if i % 2 == 0) println(i)
2.)
I always see the following symbol => but they never explain what it does.
Sometimes I think it is a cast but then it is something completely different, I hope you can clear things up.
1.) Yes, there is a difference, the first if a normal if statement inside of the closure you pass to the for-comprehension. The second is an actual guard. It will actually call withFilter on the range, before calling foreach. So the translation of the two things will look like this:
0.to(10).foreach(i => if(i % 2 == 0) println(i) )
0.to(10).withFilter(x => x % 2 == 0).foreach(i => println(i))
To add a little more context, calling withFilter or even just filter instead of using a normal if statement has some benefits. In a for comprehension, you can have nested calls to map, flatmap, filter, collect etc. so if you add guards, you can prevent a lot af calls from actually happening. For example:
for {
x <- 0 until 10
y <- 10 until 20
} {
if(x % 2 == 0) println(x*y)
}
would call the actual closure 100 times
for {
x <- 0 until 10
if x % 2 == 0
y <- 10 until 20
} println(x*y)
this will only call it 50 times, while the result stays the same.
2.)
=> separates the argument list of a function/closure from the body.
This case e: NumberFormatException => None is a part of a partial function. Here the => separates the "argument" e from the body None.
In a type signature like in someFunction(i: (A) => Int) it implies that i is of the type Function1[A,Int], read "function from A to Int".