Why does Scala fail to compile this function as tail recursive? - scala

If I replace the first line of the following recursive depth first search function with the lines commented out within the foreach block, it will fail to compile as a tail recursive function (due to the #tailrec annotation) even though the recursion is still clearly the last action of the function. Is there a legitimate reason for this behavior?
#tailrec def searchNodes(nodes: List[Node], visitedNodes: List[Node], end: String, currentLevel: Int) : Int = {
if (nodes.exists(n => n.id == end)) return currentLevel
val newVisitedNodes = visitedNodes ::: nodes
var nextNodes = List[Node]()
nodes.foreach(n => {
/*
if (n.id == end){
return currentLevel
}
*/
nextNodes = nextNodes ::: n.addAdjacentNodes(visitedNodes)
})
if (nextNodes.size == 0) return -1
return searchNodes(nextNodes, newVisitedNodes, end, currentLevel + 1)
}

As the other answer explains, using return in scala is a bad idea, and an anti-pattern. But what is even worse is using a return inside a lambda function (like your commented out code inside foreach): that actually throws an exception, that is then caught outside to make the main function exit.
As a result, the body of your function is compiled into something like:
def foo(nodes: List[Node]) = {
val handle = new AnyRef
try {
nodes.foreach { n =>
if(n.id == "foo") throw new NonLocalReturnControl(handle, currentLevel)
...
foo(nextNodes)
} catch {
case nlrc: NonLocalReturnControl[Int] if nlrc.key == handle => nlrc.value
}
}
As you can see, your recursive call is not in a tail position here, so compiler error is legit.
A more idiomatic way to write what you want would be to deconstruct the list, and use the recursion itself as the "engine" for the loop:
def searchNodes(nodes: List[Node], end: String) = {
#tailrec def doSearch(
nodes: List[(Node, Int)],
visited: List[Node],
end: String
) : Int = nodes match {
case Nil => -1
case (node, level) :: tail if node.id == end => level
case (node, level) :: tail =>
doSearch(
tail ::: node.addAdjacentNodes(visited).map(_ -> level+1),
node :: visited,
end
)
}
doSearch(nodes.map(_ -> 0), Nil, end)
}

I'm not sure exactly what the compiler is thinking, but I think all your return statements will be causing problems.
Using return is an antipattern in scala - you don't need to write it, and you shouldn't. To avoid it, you'll have to restructure your if ... return blocks as if ... value ... else ... other value blocks.
This shape is possible because everything is an expression (sort of). Your def has a value, which is defined by an if ... else block, where the if and the else both have values, and so on all the way down. If you want to ignore the value of something you can just put a new line after it, and the return value of a block is always the value of the last expression in it. You can do that to avoid having to rewrite your foreach, but it would be better to write it functionally, as a map.

Related

Scala unused expression error with if statement

I'm very new to Scala, and tried to write a simple Scala program that gets the maximum value. I found something weird (probably a language-specific feature). Here it is:
def max(xs: List[Int]): Int = {
if (xs.isEmpty) {
throw new java.util.NoSuchElementException
}
def maxAux(x: List[Int], curMax: Int): Int = {
if (x.isEmpty) {
curMax
}
if (x.head > curMax) {
maxAux(x.tail, x.head)
}
else {
maxAux(x.tail, curMax)
}
}
maxAux(xs.tail, xs.head)
}
}
For some reason, inside of maxAux function, the return of the first if statement gives me an IntelliJ warning that it is an "unused expression". Turns out it is correct because that line doesn't seem to return. To get around that issue, the second if statement in maxAux I changed to an else if, and then everything worked as intended. The other fix would be to add a return statement before curMax, but apparently using return is bad style/practice.
TL;DR: Can anyone explain why in the code above curMax doesn't return?
The immediate problem is that Scala returns the value of the last expression in a block which is the second if/else expression. So the value of the first if is just discarded. This can be fixed by making the second if an else if so that it is a single expression.
A better solution is to use match, which is the standard way of unpicking a List:
def maxAux(x: List[Int], curMax: Int): Int =
x match {
case Nil =>
curMax
case max :: tail if max > curMax =>
maxAux(tail, max)
case _ :: tail =>
maxAux(tail, curMax)
}
In def maxAux, the control-flow can enter the first if-branch, whose body yields curMax. But that if-statement is not the last statement in maxAux, another if- or else-branch will follow, and they determine the result.
If you test your function (note that your code currently doesn't compile!), e.g. via println(max(List(1,3,2,5,0))), then you'll get a NoSuchElementException, which is a consequence of your current (incorrect) implementation.
You have various options now, e.g. the following two, which only minimally change your code:
Fix the if-else cascade (which you could also rewrite into a pattern matching block):
if (x.isEmpty) {
curMax
} else if (x.head > curMax) {
maxAux(x.tail, x.head)
} else {
maxAux(x.tail, curMax)
}
Use a return statement (though you should be careful with the use of return in Scala. See the comments under this answer):
if (x.isEmpty) {
return curMax
}

why does scala compile error on if else statement?

this is a scala code:
def otpu (start : Int, end : Int) : List[Int] = {
// TODO: Provide definition here.
if(start<end)
Nil
else if(start>end){
val list0:List[Int] = start::otpu(start-1,end)
list0
}
else if(start==end){
val list:List[Int] = List(end)
list
}
}
It works like otpu(5,1)=> List(5,4,3,2,1)
But when I compile,
I get a compiler error type mismatch, found: unit,require:List[Int]" at "if(start==end)".
When I delete if(start==end) and there is just else then it works.
Why does it not work with if(start==end)?
Consider the following.
val result = if (conditionA) List(9)
This is incomplete. What if conditionA is false? What is the value of result in that case? The compiler resolves this problem by silently competing the statement.
val result = if (conditionA) List(9) else ()
But now there's a new problem. () is of type Unit. (It's the only value of that type.) Your otpu method promises to return a List[Int] but the silent else clause doesn't do that. Thus the error.
The compilation error is due to the return type mismatch in if,elseif & else condition. As in above code else is missing, therefore the compiler fails to returns the value if & elseif condition are not satisfied.
def otpu(start: Int, end: Int): List[Int] = {
// TODO: Provide definition here.
if (start < end)
Nil
else if (start > end) {
val list0: List[Int] = start :: otpu(start - 1, end)
list0
}
else if (start == end) {
val list: List[Int] = List(end)
list
}
else Nil
}
As stated in the other answers you are missing the last else condition.
You can get that immediately if you convert the code to use pattern-matching, for instance:
def otpu (start : Int, end : Int) : List[Int] = {
start match {
case `end` => List(end)
case _ if start > end => start::otpu(start-1, end)
case _ => Nil
}
}
EDIT:
I noticed the tag recursion in the question and I thought you might want to end up with a recursive function for this. The way you implemented the recursive function is not really safe due to the fact that for a very (very) large list to be produced in output, you might incur in a stack overflow runtime error. To avoid that, Scala gives you the possibility of using tail-recursive functions. Here how it would look like:
def otpu(start: Int, end: Int) : List[Int] = {
import scala.annotation.tailrec
#tailrec
def f(e: Int, acc: List[Int]): List[Int] = {
start >= e match {
// base step
case false => acc
// recursive step
case true => f(e+1, e::acc)
}
}
// call the recursive function with the empty accumulator
f(end, Nil)
}

How does Scala return in function

I implemented to find max value in the list.
I know that in Scala, You don't have to use 'return', just drop it.
So I wrote like this,
def max(xs: List[Int]):Int={
if(xs.isEmpty) throw new java.util.NoSuchElementException
def f(cur_max:Int, xs:List[Int]):Int={
if(xs.isEmpty)
cur_max // <- it doesn't return value but just keep going below code.
if(cur_max < xs.head)
f(xs.head,xs.tail)
else
f(cur_max,xs.tail)
}
f(xs.head,xs)
}
When it traversed to end of List, it should be returned cur_max value.
However, It just keeps going. Why doesn't it return cur_max.
To fix this problem, I put 'return' expression that Scala doesn't recommend like ('return cur_max').
In Scala it is not enought just to drop value - method returns last evaluated statement. In your case you have two statements:
if(xs.isEmpty)
cur_max
and
if(cur_max < xs.head)
f(xs.head,xs.tail)
else
f(cur_max,xs.tail)
So the result of second expression one gets returned.
To fix it add else statement:
if(xs.isEmpty)
cur_max
else if(cur_max < xs.head)
f(xs.head,xs.tail)
else
f(cur_max,xs.tail)
made several changes. some of them just code style to be more readable like having brackets on if expressions.
def max(xs: List[Int]): Int = {
def f(cur_max: Int, xs: List[Int]): Int = {
if (xs.isEmpty) {
cur_max // <- it doesn't return value but just keep going below code.
} else {
if (cur_max < xs.head) {
f(xs.head, xs.tail)
}
else {
f(cur_max, xs.tail)
}
}
}
if (xs.isEmpty) {
throw new java.util.NoSuchElementException
} else {
f(xs.head, xs.tail)
}
}
basically there are some cases on your inner function, which you named f:
the list is empty -> you should return the current max value
the list is not empty AND the current max is smaller than the first element of the remaining list -> update the current max and call the function with the list tail
the list is not empty AND the current max is >= than the first element of the remaining list -> call the function with the list tail and the same current max

How do you print an integer value within an object in scala?

object perMissing {
def solution(A: Array[Int]): Int = {
def findMissing(i: Int, L: List[Int]): Int = {
if (L.isEmpty || L.head != i+1) {
i+1
println(i+1)}
else findMissing(i+1, L.tail)
}
if (A.length == 0) 1
else findMissing(0, A.toList.sorted)
}
solution(Array(2,3,1,5))
}
I'm new to the world of Scala. I come from Python and C world.
How do we print an integer value, eg. for debugging? For instance, if I want to see the value of i in every iteration.
I compile my code using scalac and run it using scala.
According to the signature of your findMissing function, it should return an Int. However, if you look at the implementation of that function, only one of the code paths (namely the else part) returns an Int - the if part on the other hand does not return anything (besides Unit), since the call to println is the last line of that particular code block. To fix this issue, just return the increased value by putting it at the end of the block:
def findMissing(i: Int, l: List[Int]): Int = {
val inc = i + 1
if (l.isEmpty || l.head != inc) {
println(inc)
inc
}
else findMissing(inc, l.tail)
}
Since findMissing is tail recursive, you could additionally annotate it with #tailrec to ensure it will be compiled with tail call optimization.

How to yield a single element from for loop in scala?

Much like this question:
Functional code for looping with early exit
Say the code is
def findFirst[T](objects: List[T]):T = {
for (obj <- objects) {
if (expensiveFunc(obj) != null) return /*???*/ Some(obj)
}
None
}
How to yield a single element from a for loop like this in scala?
I do not want to use find, as proposed in the original question, i am curious about if and how it could be implemented using the for loop.
* UPDATE *
First, thanks for all the comments, but i guess i was not clear in the question. I am shooting for something like this:
val seven = for {
x <- 1 to 10
if x == 7
} return x
And that does not compile. The two errors are:
- return outside method definition
- method main has return statement; needs result type
I know find() would be better in this case, i am just learning and exploring the language. And in a more complex case with several iterators, i think finding with for can actually be usefull.
Thanks commenters, i'll start a bounty to make up for the bad posing of the question :)
If you want to use a for loop, which uses a nicer syntax than chained invocations of .find, .filter, etc., there is a neat trick. Instead of iterating over strict collections like list, iterate over lazy ones like iterators or streams. If you're starting with a strict collection, make it lazy with, e.g. .toIterator.
Let's see an example.
First let's define a "noisy" int, that will show us when it is invoked
def noisyInt(i : Int) = () => { println("Getting %d!".format(i)); i }
Now let's fill a list with some of these:
val l = List(1, 2, 3, 4).map(noisyInt)
We want to look for the first element which is even.
val r1 = for(e <- l; val v = e() ; if v % 2 == 0) yield v
The above line results in:
Getting 1!
Getting 2!
Getting 3!
Getting 4!
r1: List[Int] = List(2, 4)
...meaning that all elements were accessed. That makes sense, given that the resulting list contains all even numbers. Let's iterate over an iterator this time:
val r2 = (for(e <- l.toIterator; val v = e() ; if v % 2 == 0) yield v)
This results in:
Getting 1!
Getting 2!
r2: Iterator[Int] = non-empty iterator
Notice that the loop was executed only up to the point were it could figure out whether the result was an empty or non-empty iterator.
To get the first result, you can now simply call r2.next.
If you want a result of an Option type, use:
if(r2.hasNext) Some(r2.next) else None
Edit Your second example in this encoding is just:
val seven = (for {
x <- (1 to 10).toIterator
if x == 7
} yield x).next
...of course, you should be sure that there is always at least a solution if you're going to use .next. Alternatively, use headOption, defined for all Traversables, to get an Option[Int].
You can turn your list into a stream, so that any filters that the for-loop contains are only evaluated on-demand. However, yielding from the stream will always return a stream, and what you want is I suppose an option, so, as a final step you can check whether the resulting stream has at least one element, and return its head as a option. The headOption function does exactly that.
def findFirst[T](objects: List[T], expensiveFunc: T => Boolean): Option[T] =
(for (obj <- objects.toStream if expensiveFunc(obj)) yield obj).headOption
Why not do exactly what you sketched above, that is, return from the loop early? If you are interested in what Scala actually does under the hood, run your code with -print. Scala desugares the loop into a foreach and then uses an exception to leave the foreach prematurely.
So what you are trying to do is to break out a loop after your condition is satisfied. Answer here might be what you are looking for. How do I break out of a loop in Scala?.
Overall, for comprehension in Scala is translated into map, flatmap and filter operations. So it will not be possible to break out of these functions unless you throw an exception.
If you are wondering, this is how find is implemented in LineerSeqOptimized.scala; which List inherits
override /*IterableLike*/
def find(p: A => Boolean): Option[A] = {
var these = this
while (!these.isEmpty) {
if (p(these.head)) return Some(these.head)
these = these.tail
}
None
}
This is a horrible hack. But it would get you the result you wished for.
Idiomatically you'd use a Stream or View and just compute the parts you need.
def findFirst[T](objects: List[T]): T = {
def expensiveFunc(o : T) = // unclear what should be returned here
case class MissusedException(val data: T) extends Exception
try {
(for (obj <- objects) {
if (expensiveFunc(obj) != null) throw new MissusedException(obj)
})
objects.head // T must be returned from loop, dummy
} catch {
case MissusedException(obj) => obj
}
}
Why not something like
object Main {
def main(args: Array[String]): Unit = {
val seven = (for (
x <- 1 to 10
if x == 7
) yield x).headOption
}
}
Variable seven will be an Option holding Some(value) if value satisfies condition
I hope to help you.
I think ... no 'return' impl.
object TakeWhileLoop extends App {
println("first non-null: " + func(Seq(null, null, "x", "y", "z")))
def func[T](seq: Seq[T]): T = if (seq.isEmpty) null.asInstanceOf[T] else
seq(seq.takeWhile(_ == null).size)
}
object OptionLoop extends App {
println("first non-null: " + func(Seq(null, null, "x", "y", "z")))
def func[T](seq: Seq[T], index: Int = 0): T = if (seq.isEmpty) null.asInstanceOf[T] else
Option(seq(index)) getOrElse func(seq, index + 1)
}
object WhileLoop extends App {
println("first non-null: " + func(Seq(null, null, "x", "y", "z")))
def func[T](seq: Seq[T]): T = if (seq.isEmpty) null.asInstanceOf[T] else {
var i = 0
def obj = seq(i)
while (obj == null)
i += 1
obj
}
}
objects iterator filter { obj => (expensiveFunc(obj) != null } next
The trick is to get some lazy evaluated view on the colelction, either an iterator or a Stream, or objects.view. The filter will only execute as far as needed.