Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert backtracking algorithm to stream?

Is there any way to define a stream with a backtracking algorithm in Scala ?

For instance, the following backtracking algorithm prints all "binary" strings of a given size.

def binaries(s:String, n:Int) {
  if (s.size == n)
    println(s)
  else {
    binaries(s + '0', n)
    binaries(s + '1', n)
  }
}

I believe I can define a stream of "binary" strings of a given size using another iterative algorithm. However I wonder if I can convert the backtracking algorithm above to a stream.

like image 745
Michael Avatar asked Dec 24 '11 16:12

Michael


2 Answers

This is pretty straight-forward:

def binaries(s: String, n: Int): Stream[String] = 
  if (s.size == n) Stream(s) 
  else binaries(s + "0", n) append binaries(s + "1", n)

Note the use of append -- this method is non-standard for other collections, which is a requirement because it has to take its parameter by-name.

like image 179
Daniel C. Sobral Avatar answered Sep 21 '22 12:09

Daniel C. Sobral


You can, but it won't evaluate lazily:

def bin(s: String, n: Int): Stream[String] = {
  if (s.length == n) { 
    println("got " + s) // for figuring out when it's evaluated
    Stream(s)
  } else {
    val s0 = s + '0'
    val s1 = s + '1'
    bin(s0, n) ++ bin(s1, n)
  }
}

For instance, when executing bin("", 2).take(2).foreach(println), you'll get the following output:

scala> bin("", 2).take(2).foreach(println)
got 00
got 01
got 10
got 11
00
01

If you don't mind using a TraversableView you can use the conversion described here https://stackoverflow.com/a/3816012/257449. So then the code becomes:

def toTraversable[T]( func : (T => Unit) => Unit) = new Traversable[T] {
  def foreach[X]( f : T => X) = func(f(_) : Unit)                       
}  

def bin2(str: String, n: Int) = {
  def recurse[U](s: String, f: (String) => U) {
    if (s.length == n) { 
      println("got " + s) // for figuring out when it's evaluated
      f(s)
    } else {
      recurse(s + '0', f)
      recurse(s + '1', f)
    }
  }
  toTraversable[String](recurse(str, _)) view
}

Then

scala> bin2("", 2).take(2).foreach(println)
got 00
00
got 01
01
got 10
like image 40
huynhjl Avatar answered Sep 18 '22 12:09

huynhjl