def fib(n: Int, a: Int, b: Int): Int = {
if (n > 0)
fib(n - 1, b, a + b)
else
a
}
Unfortunately Java cannot express self tail recursive functions and Scala too can't express mutual tail recursive functions, as that would require runtime support.But you know what? That mutable loop is totally fine, because any mutation it has is encapsulated, the function itself being pure.
Python iterative solution
1. def fib(n):
2. i, curr, next = 0, 0, 1
3. while i < n:
4. i += 1
5. curr, next = next, curr + next
6. return curr
Python tail-recursive solution* 1. def fib(n):
2. def fib_tail(i, curr, next): #1
3. if i >= n: #2
4. return curr #3
5. return fib_tail(i+1, next, curr+next) #4
6. return fib_tail(0, 0, 1)
Some explanation of the 1-1 conversion process:#1. We need a helper function, `fib_tail` to keep track of the variables we update in the while loop. (lines 4-5 in iterative)
#2-3. Return `curr` when the opposite of the while condition is met. (lines 3,6 in iterative)
#4. Recursively call `fib_tail`, using same update logic as while loop body when passing arguments. (line 5 in iterative)
#5. Call helper function with initial values for the additional variables (line 1 in iterative)
* We're going to pretend that Python supports tail recursion. It doesn't, but I figure more people are familiar with python; think of it more as pseudocode for instruction. You could easily implement the above in something like Scheme
fib = 0:1:zipWith (+) fib (drop 1 fib)
[I know that `drop 1` is just `tail`, but this one makes the intent clearer for those who may not know Haskell]. let generated: Vec<i32> =
itertools::iterate((0, 1), |&(a, b)| (b, a + b))
.map(|s| s.0)
.take(10)
.collect();
Arguably, this is closer to the matrix form of Fibonacci series[1]. In addition, the same code structure can generalize to any series with a recursive definition in the form of: a_n = f(a_{n-1}, a_{n-2}, ..., a_{n-k}) - which by some standard expresses intent better. Especially, for some k, the mental overhead of a loop version is too much to bare :)[1] https://wikimedia.org/api/rest_v1/media/math/render/svg/c795...
Toy examples are toys; they're usually easily broken, since the simplicity required for pedagogy leaves a poor ratio of problem difficulty to solution power. I wouldn't write the example code as a stream either, but I much prefer the approach when the complexity level increases only slightly.