2
\$\begingroup\$

Please critique my implementation of a tail-recursive method for generating the Fibonacci sequence:

def fib(n: Int): Option[Int] = {
 @tailrec
 def go(count: Int, prev: Int, acc: Int): Option[Int] = {
 if (count == n) Some( acc )
 else go(count+1, acc, acc + prev)
 }
 if ( n < 0) None
 else if ( n == 0 ) Some( 0 )
 else if ( n == 1) Some ( 1 )
 else go(2, 1, 1)
}
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Jan 29, 2015 at 4:12
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Did you have any particular design goals while reinventing-the-wheel? There are alternative solutions, such as a lazy stream. \$\endgroup\$ Commented Jan 29, 2015 at 4:39

2 Answers 2

4
\$\begingroup\$

go is under your control, you can guarantee that it will always have a result, so you don't need to use Option for it. Also, the special cases for 0 and 1 are not neccessary. Counting backwards instead of forwards is more a matter of taste here, but it does reduce the dependency on the outer context.

def fib(n: Int): Option[Int] = {
 @tailrec
 def go(count: Int, prev: Int, acc: Int): Int = {
 if (count == 0) acc else go(count-1, acc, acc + prev)
 }
 if ( n < 0) None else Some(go(n, 1, 0))
}

However, if you want a really fast implementation (only interesting when you use BigInt), you should use these formulas, where you need only ~log(n) iterations instead of n:

$$ \begin{align} F_{2n-1} &= F_n^2 + F_{n-1}^2 \\ F_{2n} &= (F_{n-1} + F_{n+1}) F_n \\ &= (2F_{n-1} + F_n) F_n \end{align} $$

200_success
145k22 gold badges190 silver badges478 bronze badges
answered Jan 29, 2015 at 10:38
\$\endgroup\$
3
\$\begingroup\$

Option is not an appropriate type to return here. There is no doubt about whether a particular input can return a result or not; anything below zero will fail, anything above it will succeed. For once, failing hard is acceptable in the case of invalid input.

if...else if...else if...else chains are fragile and smelly in any language and really never necessary in Scala. Here, you are testing on precisely the same value each time. Use pattern matching.

 n match {
 case _ if n < 0 => ...
 case _ if n == 0 => ...
 case _ => ...
 }
answered Jan 29, 2015 at 23:07
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.