Thus, the third number is 1 (0 + 1), the fourth number is 2 (1 + 1), and that makes the fifth number 3 (1 + 2), the sixth number 5 (2 + 3) and so on ad infinitum.

There are many ways to write a program that will output the Fibonacci numbers. each method optimizes for some particular purpose. We’ll start by optimizing for being as close as possible to the written description of the numbers:

The sample above prints the numbers out to infinity. Which is the letter of the definition, but not useful for most purposes. If we only wanted, say, the first 10 or first 100, or any arbitrary number of fibonacci numbers? We’d have to weave logic about when to stop into our code:

The logic for the number of results we want is buried inside the middle of our code. Ideally, the definition of the sequence can be written completely independently of the mechanism for figuring out how many numbers we need.

And there’s another problem. How do we know what we want to do with the numbers? maybe we want to print them out, but then again, maybe we want to do something else, like stuff them in an array, or count how many are even and how many are odd?

separating concerns

Our code at the moment entangles these concerns, and our first improvement is to separate the concerns by rewriting our algorithm as a generator. Generators are an excellent way of separating “what we do with the steps of a calculation” from “how we calculate the steps.”

Our generator yields the values of the fibonacci function instead of logging them to the console. So instead of calling a function and things happen, we call fibonacci and get an iterator. That iterator can be used in a for loop, we can call its Symbol.iterator function to extract the values in sequence, or better still, we can take advantage of standard operations on generators and iterators, like take.

take is a function that turns an iterator that yields many values (even an infinite number), and yields no more than a certain number of values. We use it when we want to (cough) take a certain number of values from an iterator.

The code above calls fibonacci() to get an iterator over the Fibonacci numbers, then take(10, fibonacci()) turns that into an iterator over the first ten numbers of the Fibonacci numbers, then we run a for loop over those.

To show that we are now able to be much more flexible, here we can splat the same values into an array:

[...take(10,fibonacci())]

We won’t get into counting evens and odds just yet, we’ve already made the point that we can make our fibonacci function more readable for people by ruthlessly pairing it down to do just one thing and combining it with other functions and code externally, rather than stuffing the other code inside our function.

simplicity

Turning fibonacci into a generator requires understanding what a generator is, and how the take operation converts a generator with a possibly infinite number of values into a generator that produces a fixed number of values.

It’s almost certainly not worth learning all this just for Fibonacci numbers, but if we do learn these things and then “internalize” them, it becomes a marvellous win, because we can write something like:

And we are simply and very directly reproducing the definition as it was given to us, without cluttering it up with a lot of other concerns that dilute the basic thing we want to communicate.

But if we don’t know about generators, or we know about generators but aren’t familiar with operations like take, or we have never written a generator but vaguely know that clever people can use them to create some keywords for serializing asynchronous code but we don’t need to know how it works as long as we have an async keyword and a compiler…

Well, then, this code just looks like mathematical wankery, and we will write a blog post congratulating ourselves on doing the “simple” thing and just writing:

And then when we build larger and larger programs, at each step of the way eschewing an abstraction or technique because not using the technique we don’t know is “simpler,” and we are 100% certain at every step that we have done the right thing and avoided writing “clever” code.

It seems obvious that understanding the capabilities of our tools and how to use them in direct and obvious ways to do the things they were designed to do is not “clever.” So what is “clever code?”

clever code

Here is the naïve way to extract a particular Fibonacci number from our generator:

Take all the values up to the one we want, splat them into an array, and then take the one we want. This is very wasteful of space, and really, we’re trying to write:

constfibonacciAt=(index)=>[...fibonacci()][index];

But the way JavaScript works, that would first try to create an infinitely long array, then it would run out of space. So sticking take in the expression is mixing what we want to write with some workaround for JavaScript being an eagerly evaluated language.

Mixing two things together is not what we want to do, so even though on the surface [...take(index + 1, fibonacci())][index] looks clever because it’s so terse, it’s the wrong kind of clever.

This gives us a hint about when some inscrutable code is an abstraction that maybe we ought to learn, and when it’s just “clever:” If it’s short because it only does one thing, that’s good. If it’s short but mixes concerns, maybe it’s just clever.

If taking a set of values from an iterator is a standard operation, maybe we can separate “how we take a particular number” from “how we calculate the numbers.” Our first crack looks like this:

We are still using take as a workaround for JavaScript, but now we’ve tucked it inside the at function, and being able to write at(7, fibonacci()) is short and whatever we do with that expression won’t be cluttered up with implementation details.

For example, we could rewrite at so that it doesn’t create a long array just to ignore all but the last value:

writing for an audience

This is procedural: It’s a recipe for calculating the values one by one, as you might give it to a school child to practise arithmetic. Which is fine, but it’s just arithmetic. Math is more than arithmetic.

What if the written instructions were: “The sequence of Fibonacci numbers are the numbers 0, 1, and sum of composing the sequence with itself offset by one.” That’s a more geometric way to visualize the numbers, and it requires some mental facility with recursion and operations on sequences.

Working along those lines, the simplest implementation starts with zipWith, an operation that composes two iterators using a supplied “zipper” function:

Now, there is a performance implication of this expression, but let’s set that aside for a moment to consider: Which is better? The expression that describes composing a sequence with itself? Or the expression that describes procedurally generating numbers?

In other words, do we think in arithmetic or geometry?

The answer seems easy: If we’re talking about Fibonacci, go with geometry. It is, after all, a mathematics function. If you ever did have to write it for a program, anybody looking at the code ought to have enough of a background in mathematics to appreciate composing sequences recursively. For the same reason, if you wanted to write this:

That would be fine as well. It is math, anybody looking at it ought to have the mathematics background or be prepared to look it up. As a car driver, I expect the steering wheel in the usual place and to find the other controls as a driver would expect them. But I appreciate that the engine will be designed for the mechanically inclined.

This analogy of the driver and the automobile applies to our “geometric” expression:

Some code has multiple audiences, and separating the code’s concerns enables each piece to speak to specialists in the appropriate domain without demanding that anybody reading it be familiar with both mathematics and the efficient reuse of previously computed values.

“writing for people to read”

Code that is written in a particular domain can and should be written for programmers who are proficient with the tools of their trade. In ES6, that includes generators and common operations on sequences like take, tail, and zipWith.

Also, code that is written for a particular domain can and should be written for programmers who have domain-knowledge. A Fibonacci function should be written for the reader who has familiarity with mathematics. Code is written for humans to read, but there is a presumption that humans choosing to read it will have or be prepared to acquire the knowledge appropriate for that domain.2

When there are multiple concerns, each requiring attention to a different domain, we separate those concerns. This is why the engine of a car is hidden away from the driver and the passengers, and it is why the mechanics of computing a fibonacci number is separated from the programming issues of how to implement things like take, tail, zipWith, or memoize.