You need a mental model of your function. Let's say that you perform your function on your own, using scraps of paper for each call. First scrap, you write (fib 250000) , then you see "oh, I need to calculate (fib 249999) and (fib 249998) and finally add them", so you mark this and start two new trims. You cannot drop the first because you still have things to do when you finish other calculations. You can imagine that this calculation will require a lot of trimmings.
Another way is not to start from above, but below. How do you do it manually? You start with the first numbers, 1, 1, 2, 3, 5, 8 & hellip ;, and then always add the last two until you do it i times. You can even throw away all the numbers except the last two at each step so that you can reuse most of the crop.
(defn fib [i] (loop [a 0 b 1 n 1] (if (>= ni) b (recur b (+ ab) (inc n)))))
This is also a pretty obvious implementation, but how to do it, not that. It always seems pretty elegant when you can just write down a definition and it automatically translates into efficient calculation, but programming is a transformation. If something is transformed automatically, then this particular problem has already been solved (often in a more general way).
Thinking "how I will do it step by step on paper" often leads to good implementation.
source share