Reputation:
I want to rewrite a recursive function using pattern matching instead of if-else
statements, but I am getting (correct) warning messages that some parts of the code are unreachable. In fact, I am getting wrong logic evaluation.
The function I am trying to re-write is:
def pascal(c: Int, r: Int): Int =
if (c == 0)
1
else if (c == r)
1
else
pascal(c - 1, r - 1) + pascal(c, r - 1)
This function works as expected. I re-wrote it as follows using pattern matching but now the function is not working as expected:
def pascal2 (c : Int, r : Int) : Int = c match {
case 0 => 1
case r => 1
case _ => pascal2(c - 1, r - 1) + pascal2(c, r - 1)
}
Where am I going wrong?
Main
:
println("Pascal's Triangle")
for (row <- 0 to 10) {
for (col <- 0 to row)
print(pascal(col, row) + " ")
println()
}
Upvotes: 2
Views: 706
Reputation: 26560
I fully agree with @wheaties and advice you to follow his directions. For sake of completeness I want to point out a few alternatives.
You could write your own unapply
:
def pascal(c: Int, r: Int): Int = {
object MatchesBoundary {
def unapply(i: Int) = if (i==0 || i==r) Some(i) else None
}
c match {
case MatchesBoundary(_) => 1
case _ => pascal(c-1, r-1) + pascal(c, r-1)
}
}
I would not claim that it improves readability in this case a lot. Just want to show the possibility to combine semantically similar case
s (with identical/similar case bodies), which may be useful in more complex examples.
There is also a possible solution, which exploits the fact that Scala's syntax for pattern matching only treats lower case variables as variables for a match. The following example shows what I mean by that:
def pascal(c: Int, r: Int): Int = {
val BoundaryL = 0
val BoundaryR = r
c match {
case BoundaryL => 1
case BoundaryR => 1
case _ => pascal(c-1, r-1) + pascal(c, r-1)
}
}
Since BoundaryL
and BoundaryR
start with upper case letters they are not treated as variables, but are used directly as matching object. Therefore the above works (while changing them to boundaryL
and boundaryR
would not, which btw also gives compiler warnings). This means that you could get your example to work simply by replacing r
by R
. Since this is a rather ugly solution I mention it only for educational purposes.
Upvotes: 1
Reputation: 35980
The following statement "shadows" the variable r
:
case r =>
That is to say, the "r" in that case statement is not, in fact, the "r" that you have defined above. It is it's own "r" which is equivalently equal to "c" because you are telling Scala to assign any value to some variable named "r."
Hence, what you really want is:
def pascal2(c: Int, r: Int): Int = c match{
case 0 => 1
case _ if c == r => 1
case _ => pascal2(c-1, r-1) + pascal2(c, r-1)
}
This is not, however tail recursive.
Upvotes: 3