I'm trying to solve Project Euler question 2 with Lisp. This recursive solution blows the stack on execution, but I thought Lisp (using clisp) would recognize the tail recursion. This is being entered into the top-level.
(defun e2-problem (&optional (f1 1) (f2 1) (sum 0))
"Sum fibonacci sequence, even terms up to 4 million"
(if (> f2 4000000) sum)
(e2-problem f2 (+ f1 f2) (if (evenp f2)
(+ sum f2)
sum))
Is my implementation not correctly arranged for optimization? I imagine this would hinder my Lisp education quite a bit if I could not rely on idiomatic recursion.
1) Correct syntax error in code:
(defun e2-problem (&optional (f1 1) (f2 1) (sum 0))
"Sum fibonacci sequence, even terms up to 4 million"
(if (> f2 4000000)
sum ;; here was a closing bracket
(e2-problem f2 (+ f1 f2) (if (evenp f2)
(+ sum f2)
sum)))) ;; 2 more brackets here
2) use SBCL. CLISP is not kind enough to detect tail recursion.
3) use highest available optimization level:
(defun e2-problem (&optional (f1 1) (f2 1) (sum 0))
"Sum fibonacci sequence, even terms up to 4 million"
(declare (optimize (debug 0))) ;; optimization
...
Recursion (or even iteration) is not necessary!
Every third Fibonacci number is even:
1 1 2 3 5 8 13 21 34 55 89 144 ...
and since each even Fibonacci number (in bold) is the sum of the two preceding odd Fibonacci numbers, the sum of the even Fibonacci numbers up to Fn is exactly half of the sum of all the Fibonacci numbers up to Fn (if Fn is even, of course).
Now, the sum of the first n Fibonacci numbers is Fn+2 − 1. This is easy to check by induction: the sum of the first n + 1 Fibonacci numbers is F1 + F2 + ... + Fn + Fn+1, which equals Fn+2 − 1 + Fn+1 by hypothesis, which equals Fn+3 − 1 by the definition of the Fibonacci numbers.
So if you can find the largest N such that F3N ≤ 4,000,000, then the sum that’s asked for will be (F3N+2 − 1) / 2.
(I'll leave the remaining details to you but it should be straightforward from here.)
I thought Lisp (using clisp) would recognize the tail recursion
For an environment to implement tail call elimination is mandatory in Scheme, but not in most other Lisp dialects, such as Common Lisp.
Your code implements an endless loop. It does not terminate.
Using LOOP:
(defun e2-problem-a (n)
"Sum fibonacci sequence, even terms up to n"
(loop for f1 = 1 then f2
and f2 = 1 then (+ f1 f2)
while (<= f2 n)
when (evenp f2) sum f2))