views:

199

answers:

2

I have some mutable scala code that I am trying to rewrite in a more functional style. It is a fairly intricate piece of code, so I am trying to refactor it in pieces. My first thought was this:

def iterate(count:Int,d:MyComplexType) = {
  //Generate next value n
  //Process n causing some side effects
  return iterate(count - 1, n)
}

iterate(2000000,initialValue)

This didn't seem functional at all to me, since I still have side effects mixed throughout my code. My second thought was this:

def generateStream(d:MyComplexType):Stream[MyComplexType] = {
  //Generate next value n
  return Stream.cons(n, generateStream(n))
}

for (n <- generateStream(initialValue).take(2000000)) {
  //process n causing some side effects
}

This seemed like a better solution to me, because at least I've isolated my functional value-generation code from the mutable value-processing code. However, this is much less memory efficient because I am generating a large list that I don't really need to store.

This leaves me with 3 choices:

  1. Write a tail-recursive function, bite the bullet and refactor the value-processing code
  2. Use a lazy list. This is not a memory sensitive app (although it is performance sensitive)
  3. Come up with a new approach.

I guess what I really want is a lazily evaluated sequence where I can discard the values after I've processed them. Any suggestions?

+3  A: 

I'm thinking you want to use Range if all you're doing is creating a Seq of ints from 0 to 2000000. It's nice and lazy, in 2.7 at least.

sblundy
Sorry, I think my original question was unclear because I oversimplified it. I do not need a range from 0 to 2000000. The Seq consists of a complex data structure. Original code has been modified to reflect this.
dbyrne
+6  A: 

Bear in mind that performance-critical algorithms often work better when mutable. So beware of premature de-optimization!

In Scala 2.8 you can use Iterator.iterate to create an infinite sequence without stored values. But I'm not sure that alone will be the key step to refactoring the code to be more functional. It's that "process data with side effects" part that is tricky.

You might put the whole thing into the iterate block:

Iterator.iterate(initialState)(x => {
  // create a new state based upon state x
}).drop(2000000).next

where you now have defined an infinite processing stream by sequentially modifying your initial state. You throw away the first 2000000 values (one of which is the initial value), then get the next one (which is the 2000000'th generated value). Try it out with 0 and x=>x+1 to see it in action.

Rex Kerr
Thanks! This is EXACTLY what I was looking for!
dbyrne