2

I'm new to programming in Scala. My aim is to implement a tail-recursive program for the Towers of Hanoi problem. I believe it can be achieved by recursion like this:

// Implementing a recursive function for Towers of Hanoi,where the no of disks is taken as 'n', 'from' being the Start Peg, 'to' being the End Peg, and 'via' being Intermediate Peg

def move(n: Int, from: Int, to: Int, via: Int) : Unit = { // Recursive Function
    if (n == 1) {  
     Console.println("Move disk from pole " + from + " to pole " + to)// each move iteration printed.
 }
 else {  
    move(n - 1, from, via, to) //Moving n-1 disks from source to Intermediate
    move(1, from, to, via) // Printing all the move iterations
    move(n - 1, via, to, from) //Moving n and other n-1 disks to the final destination
  } 
}  

Can it implemented using tail-recursion as well?

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
Sammy
  • 21
  • 1
  • 2
  • I don't think there is a simple way of making that tail recursive. Tail recursion is essentially the same as an iterative loop. – Tesseract Oct 06 '13 at 05:41

2 Answers2

4

There's a way, which is moving the stack to a parameter on move. Something like this:

case class Pos(n: Int, from: Int, to: Int, via: Int)

def move(pos: Pos, rest: List[Pos]) : Unit = {
  val Pos(n, from, to, via) = pos
  if (n == 1) {
    println(s"Move disk from pole $from to pole $to")
    move(rest.head, rest.tail)
  } else {
    val pos1 = Pos(n - 1, from, via, to)
    val pos2 = Pos(1, from, to, via)
    val pos3 = Pos(n - 1, via, to from)
    move(pos1, pos2 :: pos3 :: rest)
  }
} 

This is usually the easiest way of getting tail recursion out of something which is not naturally tail recursive, because you just need to figure out what goes on the stack. Unfortunately, it can be much harder if there are operations involved other than just recursing.

Another way the problem can be solved, in Scala, is making use of non strictness, such as Stream. It would be like this:

def move(n: Int, from: Int, to: Int, via: Int): Stream[String] = {
  if (n == 1) Stream(s"Move disk from pole $from to pole $to")
  else {
    println(s"$n pins left")
    move(n - 1, from, via, to) #::: move(1, from, to, via) #::: move(n - 1, via, to, from)
  }
}

Then you just print the strings returned by move. This is not tail recursive, but the trick here is that only the first move is evaluated -- the other ones are kept as functions, and only evaluated on demand. A proper Stream (I think Scalaz has one) won't evaluate even that.

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
2

Daniel's great solution reminded me that there is a more general way of making a method tail recursive. You can use continuation passing style http://en.wikipedia.org/wiki/Continuation-passing_style

Basically if you don't want to execute the rest of a method right away you can wrap it in a function object and run it at a later time. In that context the function is called a continuation.

However I'm not sure if you can count my code as truly tail recursive. After all I had to define a second method to get the compiler to accept it as such.

import scala.annotation.tailrec

def move2(n: Int, from: Int, to: Int, via: Int)(c: => Unit) : Unit = move(n, from, to, via)(c)

@tailrec
def move(n: Int, from: Int, to: Int, via: Int)(c: => Unit) : Unit = {
  if (n == 1) {
    Console.println("Move disk from pole " + from + " to pole " + to)
    c
  } else {  
    move(n - 1, from, via, to) { // this is like creating a list made up of two continuations
      move2(1, from, to, via) {       // 1. this
        move2(n - 1, via, to, from) { // expression
        }                             // here
      }
      c // and 2. the previous continuation
    }
  }
}

move(3, 1, 3, 2){}
Tesseract
  • 8,049
  • 2
  • 20
  • 37