Scala seems to require 'return' keyword for recursive functions - scala

I'm new to Scala and know that the 'return' keyword is redundant. However, when writing a recursive function, the control doesn't return from a call stack when the desired condition is met if the 'return' keyword is missing.
Below is a code to check for balanced parentheses -
Using 'return' (works fine):
def balance(chars: List[Char]): Boolean = {
def parenBalance(char : List[Char]) :Boolean = {
parenBalanceRecur(char, 0 , 0)
}
def parenBalanceRecur(charSequence: List[Char], itr : Int, imbalance : Int) : Boolean = {
if (imbalance < 0) then return false
if (itr == charSequence.length ) {
if (imbalance == 0) then return true else return false
}
if (charSequence(itr) == '(') {
parenBalanceRecur(charSequence, (itr + 1), (imbalance + 1))
}
else if (charSequence(itr) == ')') {
parenBalanceRecur(charSequence, itr + 1, imbalance -1)
}
else {
parenBalanceRecur (charSequence, itr +1, imbalance)
}
}
parenBalance(chars)
}
Without return (Successfully computes #1, but doesn't return, fails at #2 with IndexOutOfBoundsException):
def balance(chars: List[Char]): Boolean = {
def parenBalance(char : List[Char]) :Boolean = {
parenBalanceRecur(char, 0 , 0)
}
def parenBalanceRecur(charSequence: List[Char], itr : Int, imbalance : Int) : Boolean = {
if (imbalance < 0) then false
if (itr == charSequence.length ) {
if (imbalance == 0) then true else false // #1
}
if (charSequence(itr) == '(') { // # 2
parenBalanceRecur(charSequence, (itr + 1), (imbalance + 1))
}
else if (charSequence(itr) == ')') {
parenBalanceRecur(charSequence, itr + 1, imbalance -1)
}
else {
parenBalanceRecur (charSequence, itr +1, imbalance)
}
}
parenBalance(chars)
}
Is this specific to tail recursion? Please help me understand this.

As mentioned in some comments, you can not just short circuit the path and return a value without the return keyword. return is not needed only at the last value of the method. In any case, usually, it's a good practice to avoid short circuits with multiple returns in a method.
In your example, adding two else you can construct the path down to the last value of each possible output without using the return keyword:
def balance(chars: List[Char]): Boolean = {
def parenBalance(char : List[Char]) :Boolean = {
parenBalanceRecur(char, 0 , 0)
}
#tailrec
def parenBalanceRecur(charSequence: List[Char], itr : Int, imbalance : Int) : Boolean = {
if (imbalance < 0) then false
else if (itr == charSequence.length ) {
if (imbalance == 0) then true else false // #1
}
else if (charSequence(itr) == '(') { // # 2
parenBalanceRecur(charSequence, (itr + 1), (imbalance + 1))
}
else if (charSequence(itr) == ')') {
parenBalanceRecur(charSequence, itr + 1, imbalance -1)
}
else {
parenBalanceRecur (charSequence, itr +1, imbalance)
}
}
parenBalance(chars)
}

As currently implemented, parenBalanceRecur() has 3 top-level if expressions, they each evaluate to a boolean value, but the rule in scala is that only the last expression of the function is the return value of the function => the first two are simply ignored.
=> in your second implementation:
def parenBalanceRecur(charSequence: List[Char], itr : Int, imbalance : Int) : Boolean = {
if (imbalance < 0) then false
if (itr == charSequence.length ) {
if (imbalance == 0) then true else false // #1
}
if (charSequence(itr) == '(') { // # 2
parenBalanceRecur(charSequence, (itr + 1), (imbalance + 1))
}
else if (charSequence(itr) == ')') {
parenBalanceRecur(charSequence, itr + 1, imbalance -1)
}
else {
parenBalanceRecur (charSequence, itr +1, imbalance)
}
}
parenBalance(chars)
}
The first expression if (imbalance < 0) then false will evaluate to either true or false, but this expression is disconnected from the rest of the code => the function is not doing anything with that boolean. We could as well write val thisAchievesNothing = if (imbalance < 0) then false. Our thisAchievesNothing will hold some value, which is valid syntax, but is not very useful.
Likewise, this:
if (itr == charSequence.length ) {
if (imbalance == 0) then true else false // #1
}
will evaluate to another boolean that is equally ignored.
Finally, the last if... else if... else will also evaluate to yet another boolean, and since this one is the last expression of the function, that and that only will be the returned value.
Try to re-writing parenBalanceRecur as one single if.. else if... else if ... expression instead of 3, and then the behavior will be the same as the implementation that uses return.
(we tend to avoid return since it's a statement that does something, whereas the habit is to write functions/expression that are some value)

Besides the accepted answer, some things worth considering:
use #tailrec, so your recursive method gets tail-call optimized by the compiler. Otherwise it can produce stack overflow for very large lists. (Although this might not be the case here, always consider using this annotation when implementing tail-recursive methods).
List in Scala is a singly-linked list, so it's not indexed. Using cs(iter) on each recursive call makes your method get the element in linear time for every index. That means you'll get O(n^2) complexity. As an alternative, either use chars: Array[Char] which is indexed-based and gives you each element in O(1) or continue using list but switch to pattern match instead.
minor things: redundant curly braces from if expressions with only a single statement inside; parenBalance can be removed and call directly parenBalanceRecur(char, 0 , 0) as the last statement in balance; use default values for parenBalanceRecur.
My suggestions in code:
def isBalanced(chars: List[Char]): Boolean = {
#tailrec
def balance(cs: List[Char], imbalances: Int = 0): Boolean =
if (imbalances < 0) false
else cs match {
case Nil => imbalances == 0
case x :: xs =>
if (x == '(') balance(xs, imbalances + 1)
else if (x == ')') balance(xs, imbalances - 1)
else balance(xs, imbalances)
}
balance(chars)
}
println(isBalanced("()".toList)) // true
println(isBalanced("()(())".toList)) // true
println(isBalanced(")(".toList)) // false
println(isBalanced("(()))".toList)) // false
println(isBalanced("((((()))))".toList)) // true

Related

Is there a more effective way to check if a number is prime using recursive function?

I am writing a recursive function to check if a non-negative Integer is Prime in SCALA. My function takes two inputs to do so. Here is my code:
import io.StdIn._
def isPrime (x:Int, i:Int): Boolean = {
if (i < 3) {
true
}else if (x % i == 0) {
false
}else{
isPrime(x,i-1)
}
}
print("Enter a number to check if it is a prime number: " )
val num1 = readInt()
println(isPrime(num1,num1-1))
My question is that is there a way for me to take one input as the parameter for the function? The code has to use a recursive function. I know that there are more effective ways to check if a number is prime (using iteration perhaps), but I'm just doing this as a practice problem.
It is perfectly fine, I'd say even standard practice, to wrap recursive functions with a calling function. For example:
def isPrime( x:Int ) = {
def recIsP( n:Int, i:Int ) : Boolean = i == n || n % i != 0 && recIsP(n, i + 1)
recIsP(x,2)
}
isPrime(3301)
One option is to make an inner method
def isPrime(x:Int): Boolean = {
def loop(i: Int): Boolean =
if (i<3 ) {
true
} else if (x % i==0) {
false
} else {
isPrime(x,i-1)
}
loop(x, x - 1)
}
another option is to make a default parameter. Those can't refer back to the previous parameter, so you'll have to use a workaround. Here I pass some j, and make i = x - j, so I can just increment j starting from 1
def isPrime(x: Int, j: Int = 1): Boolean = {
val i = x - j
if (i < 3) {
true
} else if (x % i==0) {
false
} else {
isPrime(x, j + 1)
}
}
Unrelatedly, there is a bug in your code: 4 should not be prime.

How to remove' identifier expected but integer literal found error' in Scala?

I am trying to build a function to identify if a an expresson has balanced parenthesis or not.
My problem is that I am getting this error on my functions for the variables opening_index and closing_index :
Error:(3, 30) identifier expected but integer literal found.
var opening_index: Int =-1
Error:(6, 30) identifier expected but integer literal found.
var closing_index: Int =-1
Error:(34, 30) identifier expected but integer literal found.
var opening_index: Int =-1
Error:(37, 30) identifier expected but integer literal found.
var closing_index: Int =-1
I have been googling my error for the last hour without finding any valuable cluses.
Here is my code:
object Test
{
def balance(chars: List[Char]): Boolean=
{
var opening_index: Int =-1
var closing_index: Int =-1
opening_index=chars.indexOf('(')
closing_index=chars.indexOf(')')
if (opening_index ==-1 && closing_index==-1)
{
true
}
if (closing_index>-1 && opening_index>-1)
{
if (closing_index<=opening_index) return(false)
else
{
balance(chars.drop(closing_index).drop(opening_index))
}
}
else
return (false)
}
}
The tokenizer doesn't know, where a token ends or starts. Use some delimiters, which makes the code more readable for humans too:
object Test {
def balance(chars: List[Char]): Boolean =
{
var opening_index: Int = -1
var closing_index: Int = -1
opening_index=chars.indexOf ('(')
closing_index=chars.indexOf (')')
if (opening_index == -1 && closing_index == -1)
{
true
}
if (closing_index > -1 && opening_index > -1)
{
if (closing_index <= opening_index)
return false
else
balance (chars.drop (closing_index).drop (opening_index))
}
else
return false
}
}
Since you only initialize your vars to reinitialize them directly again, you can easily earn some functional points by declaring them as vals:
def balance (chars: List[Char]): Boolean =
{
val opening_index: Int = chars.indexOf ('(')
val closing_index: Int = chars.indexOf (')')
For recursive calls, you don't have to bother - those generate a new pair of values which don't interfere with those of the calling context.
You might also note, that return statements dont need a function-call-look with parens return (false) but can be written as return false, and even the return keyword is most of the time superflous.
object Test {
def balance (chars: List[Char]): Boolean =
{
val opening_index: Int = chars.indexOf ('(')
val closing_index: Int = chars.indexOf (')')
if (opening_index == -1 && closing_index == -1)
{
true // but note the else in the 2nd next line
}
else if (closing_index > -1 && opening_index > -1)
{
if (closing_index <= opening_index)
false
else
balance (chars.drop (closing_index).drop (opening_index))
}
else
false
}
}
When Scala sees =-1, it gets tokenized (split) not as = -1 (as in other languages you may be familiar with), but as =- 1, since =- is a perfectly fine identifier in Scala.
Since = hasn't been seen, the entire Int =- 1 must be a type. By infix notation for types, it's equivalent to =-[Int, 1]. Except 1 here must be a type. To be a type it should start with an identifier, and that's what the error message is saying. If you fixed that, it would complain about unknown =- type next.
This can be simplified by just counting how many of each there are and seeing if the numbers match up:
def balance (chars: List[Char]): Boolean = {
val opening = chars.count(_ == '(')
val closing = chars.count(_ == ')')
opening == closing
}
balance(List('(', ')', '(', ')', '(')) //false
balance(List('(', ')', '(', ')')) //true
If you want the balanced parentheses to be in order, you can do it recursively:
def balance(chars: List[Char], open: Int = 0): Boolean = {
if (chars.isEmpty)
open == 0
else if (chars.head == '(')
balance(chars.tail, open + 1)
else if (chars.head == ')' && open > 0)
balance(chars.tail, open - 1)
else
balance(chars.tail, open)
}
val x = "(apple + pear + (banana)))".toList
balance(x) //true
val y = "(()(".toList
balance(y) //false
This goes through every element of the list and adds/subtracts to/from a variable called open until the list is empty, at which point if open is 0 it returns true otherwise it returns false.

Scala Do While Loop Not Ending

I'm new to scala and i'm trying to implement a do while loop but I cannot seem to get it to stop. Im not sure what i'm doing wrong. If someone could help me out that would be great. Its not the best loop I know that but I am new to the language.
Here is my code below:
def mnuQuestionLast(f: (String) => (String, Int)) ={
var dataInput = true
do {
print("Enter 1 to Add Another 0 to Exit > ")
var dataInput1 = f(readLine)
if (dataInput1 == 0){
dataInput == false
} else {
println{"Do the work"}
}
} while(dataInput == true)
}
You're comparing a tuple type (Tuple2[String, Int] in this case) to 0, which works because == is defined on AnyRef, but doesn't make much sense when you think about it. You should be looking at the second element of the tuple:
if (dataInput1._2 == 0)
Or if you want to enhance readability a bit, you can deconstruct the tuple:
val (line, num) = f(readLine)
if (num == 0)
Also, you're comparing dataInput with false (dataInput == false) instead of assigning false:
dataInput = false
Your code did not pass the functional conventions.
The value that the f returns is a tuple and you should check it's second value of your tuple by dataInput1._2==0
so you should change your if to if(dataInput1._2==0)
You can reconstruct your code in a better way:
import util.control.Breaks._
def mnuQuestionLast(f: (String) => (String, Int)) = {
breakable {
while (true) {
print("Enter 1 to Add Another 0 to Exit > ")
f(readLine) match {
case (_, 0) => break()
case (_,1) => println( the work"
case _ => throw new IllegalArgumentException
}
}
}
}

In what order / how does Scala evaluate conditionals inside a function definition?

While trying to write a simple parentheses balancing function, I learned that I do not know how scala evaluates if-statements.
def balance(chars: List[Char]): Boolean = {
def loop(chars: List[Char], opened: Int): Boolean = {
println(opened)
println(chars.head)
if (opened < 0) return false
if (chars.isEmpty && opened == 0) return true
if (chars.isEmpty && opened > 0) return false
if (!chars.isEmpty && chars.head.toString == "(") loop(chars.tail, opened+1)
if (!chars.isEmpty && chars.head.toString == ")") loop(chars.tail, opened-1)
else loop(chars.tail, opened)
}
loop(chars, 0)
}
When I run this, by the third iteration, it will println(opened) and claim opened = -1. I imagined that (opened < 0) ----> (-1 < 0) -----> true, so I will return false. This is not the case - why?
Scala evaluates if expressions in the order they are declared. The problem with this algo is that it is assuming that the last else expression will only be evaluated if no other if condition is true, but with an input '(X))' you will create two recursion trees: one for the condition !chars.isEmpty && chars.head.toString == "(" and another in else loop(chars.tail, opened). That creates the impression that the recursion is not ending when opened =-1 but in fact what you are seeing is the 'else' recursion tree.
Solution? You are just missing an else:
if (!chars.isEmpty && chars.head.toString == "(") loop(chars.tail, opened+1) **else**
(Note: this code can probably be improved using a match...case statement. That will prevent the previous else issue from happening.
Also, you can compare chars with chars. No need to turn them into strings: chars.head.toString == "(" => chars.head == '(' )
* EDIT *
After your comment, here's how you could use pattern matching on your list structure:
def loop(chars: List[Char], opened: Int): Boolean = {
if (opened < 0) return false else
chars match {
case Nil => opened == 0
case '('::tail => loop(tail, opened + 1)
case ')'::tail => loop(tail, opened -1)
case x::tail => loop(tail, opened)
}
I hope this helps.

Why do I have "Type mismatch; Found Unit, expected Boolean" in Scala-IDE?

I've got the following Scala code(ported from a Java one):
import scala.util.control.Breaks._
object Main {
def pascal(col: Int, row: Int): Int = {
if(col > row) throw new Exception("Coloumn out of bound");
else if (col == 0 || col == row) 1;
else pascal(col - 1, row - 1) + pascal(col, row - 1);
}
def balance(chars: List[Char]): Boolean = {
val string: String = chars.toString()
if (string.length() == 0) true;
else if(stringContains(")", string) == false && stringContains("(", string) == false) true;
else if(stringContains(")", string) ^ stringContains("(", string)) false;
else if(getFirstPosition("(", string) > getFirstPosition(")", string)) false;
else if(getLastPosition("(", string) > getLastPosition(")", string)) false;
else if(getCount("(", string) != getCount(")", string)) false;
var positionOfFirstOpeningBracket = getFirstPosition("(", string);
var openingBracketOccurences = 1; //we already know that at the first position there is an opening bracket so we are incrementing it right away with 1 and skipping the firstPosition variable in the loop
var closingBracketOccurrences = 0;
var positionOfClosingBracket = 0;
breakable {
for(i <- positionOfFirstOpeningBracket + 1 until string.length()) {
if (string.charAt(i) == ("(".toCharArray())(0)) {
openingBracketOccurences += 1;
}
else if(string.charAt(i) == (")".toCharArray())(0) ) {
closingBracketOccurrences += 1;
}
if(openingBracketOccurences - closingBracketOccurrences == 0) { //this is an important part of the algorithm. if the string is balanced and at the current iteration opening=closing that means we know the bounds of our current brackets.
positionOfClosingBracket = i; // this is the position of the closing bracket
break;
}
}
}
val insideBrackets: String = string.substring(positionOfFirstOpeningBracket + 1, positionOfClosingBracket)
balance(insideBrackets.toList) && balance( string.substring(positionOfClosingBracket + 1, string.length()).toList)
def getFirstPosition(character: String, pool: String): Int =
{
for(i <- 0 until pool.length()) {
if (pool.charAt(i) == (character.toCharArray())(0)) {
i;
}
}
-1;
}
def getLastPosition(character: String, pool: String): Int =
{
for(i <- pool.length() - 1 to 0 by -1) {
if (pool.charAt(i) == (character.toCharArray())(0)) {
i;
}
}
-1;
}
//checks if a string contains a specific character
def stringContains(needle: String, pool: String): Boolean = {
for(i <- 0 until pool.length()) {
if(pool.charAt(i) == (needle.toCharArray())(0)) true;
}
false;
}
//gets the count of occurrences of a character in a string
def getCount(character: String, pool: String) = {
var count = 0;
for ( i <- 0 until pool.length()) {
if(pool.charAt(i) == (character.toCharArray())(0)) count += 1;
}
count;
}
}
}
The problem is that the Scala IDE(lates version for Scaal 2.10.1) gives the following error at line 78(on which there is a closin brace): "Type mismatch; Found Unit, expected Boolean". I really can't understand what the actual problem is. The warning doesn't give any information where the error might be.
In Scala (and most other functional languages) the result of a function is the value of the last expression in the block. The last expression of your balance function is the definition of function getCount, which is of type Unit (the Scala equivalent of void), and your function is declared as returning a Boolean, thus the error.
In practice, you've just screwed up your brackets, which would be obvious if you used proper indentation (Ctrl+A, Ctrl+Shift+F in scala-ide).
To make it compile, you can put the following two lines at the end of the balance method instead of in the middle:
val insideBrackets: String = string.substring(positionOfFirstOpeningBracket + 1, positionOfClosingBracket)
balance(insideBrackets.toList) && balance(string.substring(positionOfClosingBracket + 1, string.length()).toList)
You would also have to put the inner functions at the top of balance I think -- such as getCount.