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 caus开发者_运维技巧ing 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:
- Write a tail-recursive function, bite the bullet and refactor the value-processing code
- Use a lazy list. This is not a memory sensitive app (although it is performance sensitive)
- 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?
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.
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.
精彩评论