Fibonacci series in Haskell

Tags: / haskell /

Create a simple function in Haskell to generate the Fibonacci series.

(Based on a class taught by a teacher of mine.)


Nifty features of Haskell

Haskell is a purely functional programming language.

There are no statements. Only expressions. For a discussion about the difference between the two, see here.

This means a function cannot change the value of any of its parameters. They can only return values.

There are no side effects. Each expression is sort of self-contained. Whatever happens in an expression cannot affect other unrelated expressions.

So it's possible, and often helpful, to think of a Haskell program as simply a set of equations.

(No wonder mathematicians like functional programming languages like Haskell :D)

We can 'store equations' into variables in a sense. This is possible Haskell does lazy evaluation. The equation won't be evaluated till it is needed.

A few handy functions in Haskell

Let's see a few built-in functions in Haskell which can help us in our venture.

zipWith

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]

Combines two lists by applying a function to their elements position-wise. The size of the resultant list is min(len(list1, list2)).

Examples:

> zipWith (+) [1,2,3] [1,2]
[2,4]

> zipWith (*) [2,3] [4,5,6]
[8,15]

> zipWith (*) [2,3,4] [5,6,7,8]
[10,18,28]

> zipWith (-) [2,3,4] [5,6,7,8]
[-3,-3,-3]

tail

tail :: [a] -> [a]

Returns everything except the first element of a list.

Passing an empty list to tail would cause exception.

> tail []
*** Exception: tail: empty list

> tail [1]
[]

> tail [1,2,3,4]
[2,3,4]

take

take :: Int -> [a] -> [a]

Accepts an integer (n) along with a list and returns the first n elements of the list.

> take 2 [1,2,3,4]
[1,2]
> take 3 [1,2,3,4]
[1,2,3]
> take 10 [1..100]
[1,2,3,4,5,6,7,8,9,10]

'Equation' for Fibonacci series

Now that we have seen the built-in Haskell functions we'll use, let's make the Fibonacci series.

The 'equation' for the Fibonacci series may be written as:

fibo = 1 : 1 : zipWith (+) fibo (tail fibo)

Here, a list is being made. The first two elements are explicitly given (1 and 1) and the remaining elements are found based on that.

The zipWith (+) fibo (tail fibo) part basically takes two 'copies' (not really copies) of fibo, removes the first element from one of them with tail fibo and adds elements of fibo and tail fibo position-wise.

The result is the list of Fibonacci numbers.

It works something like this:

fibo     : 1 1 ...  |  1 1 2 ...  |  1 1 2 3 ...  |  1 1 2 3 5 ...
tail fibo: 1 ...    |  1 2 ...    |  1 2 3 ...    |  1 2 3 5 ...   
          --------- →  ---------- →  ------------ → --------------
zipWith  : 2        |  2 3        |  2 3 5        |  2 3 5 8      

fibo denotes the infinite list of Fibonacci numbers. But thanks to lazy evaluation, its expansion is done only to the extent that is asked for.

Getting the first 10 Fibonacci numbers is as easy doing:

> take 10 fibo
[1,1,2,3,5,8,13,21,34,55]

And we can use list indexing syntax of Haskell (ie, !!) to get the i-th Fibonacci number.

fibo !! i

where indexing starts from zero.

> fibo !! 3
3
> fibo !! 13
377
> fibo !! 15
987
> fibo !! 150
16130531424904581415797907386349

Neat, isn't it? And this is basically just a single-line program!