Recursion

Luhn
Luhn in Scala
object Luhn {

  def valid(input: String): Boolean = {
    validRecur(1, 0, input)
  }

  @scala.annotation.tailrec
  private def validRecur(pos: Int, sum: Int, input: String): Boolean = {
    if (input.isEmpty) return pos > 2 && sum % 10 == 0
    input.last match {
      case chr if chr.isDigit => {
        val num = chr.asDigit
        pos match {
          case pos if pos % 2 == 0 =>
            validRecur(
              pos + 1,
              sum + (if (num > 4) (num * 2) - 9 else num * 2),
              input.init
            )
          case _ => validRecur(pos + 1, sum + num, input.init)
        }
      }
      case chr if chr.isSpaceChar => validRecur(pos, sum, input.init)
      case _                      => false
    }
  }
}

This approach starts by returning the result of calling the recursive method, passing in 1 for the starting position, 0 for the sum, and the String input.

The validRecur() method is annotated with the @tailrec annotation to verify that the method can be compiled with tail call optimization.

A tail call is a particular form of recursion where the last call in the method is a call to the same method and nothing else.

In other words, if the last call in recurMe() is recurMe(arg1, arg2) + 1, the + 1 makes the recursion non-tail recursive.

If the last call in recurMe() is recurMe(arg1, arg2, acc + 1), then the recursion is a tail call, because only the method is being called with no other operation being peformed on it.

If the input String isEmpty, then the method returns if the position is greater than 2 and the sum is evenly divisible by 10.

Otherwise, the last character is tested in a match expression. The pattern matching first checks if the character is a digit. If so, an Int is set from the character and the position is then checked for whether it is even or odd. The validRecur() method calls itself with the sum increased according to the position, the position increased by 1, and all but the last character returned by init(). Note that the original position, sum and input are not mutated, but new arguments are created from the operations on them, thus supporting immutability.

If the character is not a letter, then it is tested for being a space. If it is a space, then the position and sum are passed into the next call ofvalidRecur() as is, along with all but the last character.

If the character is neither a digit nor a space, then the character is illegal and the method immediately returns false.

9th Oct 2024 · Found it useful?