Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The lisp-way to solve Fibonnaci

I wanted to try and learn Lisp, but I very quickly gave up. I figured I'd try again. I'm looking at Problem 2 on Project Euler - finding the sum of all even Fibonacci numbers under 4 Million.

I wrote the following code which works, but is all kinds of ugly. Chief among them is the fact that it's so slow - because it's doing naive recursion all the time.

When I wrote this program in Python I built up a list as I calculated and never recalculated numbers. I know I could do that here (somehow) but that doesn't seem to be true to the spirit of lisp, of functional programming. I gave up after #3, when I hit a recursion depth limit and had to rewrite my code to use a loop instead of recursion.

So I suppose my questions are:

  1. What's the 'right, lispy way' to solve this problem?
  2. How do you reconcile recursion and the notion of 'just calculating everything' with the practical limit of calculating everything?
  3. Any recommendations for learning lisp besides The Little Schemer, and Project Euler?

And here's my code:

 (defun fib(i)
   (if (= i 1)                   ;Could rewrite this as a case statement
     1
     (if (= i 2)
       1
       (+ (fib (- i 1)) (fib (- i 2))))))

 (defun solve(i)
   (let ((f (fib i)))            ;Store result in local variable
     (print f)                   ;For debugging
     (if (< 4000000 f)
       0                         ;return
       (if (= 0 (mod f 2))
         (+ f (solve (+ i 1)))   ;add number
         (solve (+ i 1))))))     ;don't

 (print (solve 1))
like image 537
Tom Ritter Avatar asked Mar 09 '09 18:03

Tom Ritter


People also ask

How do you memorize the Fibonacci sequence?

Classic recursive implementation of a Fibonacci function 1 is always the first and second number of the Fibonacci sequence: n :1,2,3,4,5,6, 7, 8,9 fib (n):1,1,2,3,5,8,13,21,34... We add the previous two numbers in the sequence, e.g. 5+8=13, to generate the next number in the sequence.

How does Fibonacci algorithm work?

The sequence follows the rule that each number is equal to the sum of the preceding two numbers. The Fibonacci sequence begins with the following 14 integers: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233 ... Each number, starting with the third, adheres to the prescribed formula.


1 Answers

Use tail recursion instead of naive recursion. Most Lisp implementations should perform the tailcall-optimization; no more recursion depth limit.

Beyond that, try to think of things in terms of lists and abstract operations you could perform on those lists. Two of the more relevant operations to consider:

  • filter
  • fold

Regarding other Lisp resources:

  • Common Lisp—On Lisp
  • Scheme—Structure and Interpretation of Computer Programs

UPDATE: Tail-recursive Scheme fib function:

(define (fib n)
  (fib-tr n 1 0))

(define (fib-tr n next result)
  (cond ((= n 0) result)
        (else (fib-tr (- n 1) (+ next result) next))))
like image 159
Hank Gay Avatar answered Oct 13 '22 16:10

Hank Gay