Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Representing Fibonacci numbers using a list comprehension in Haskell

I have written the following code to generate a list containing the Fibonacci numbers.

fibonacci = [a + b | a <- 1:fibonacci, b <- 0:1:fibonacci]

I would expect the output of the list to be [1,2,3,5,8,13..], however, the output is not the Fibonacci sequence.

I can't quite understand why it doesn't work.

My reasoning is that, if the Fibonacci numbers are [1,2,3,5,8,13..] then this will be equal to the sum of the 2 lists [1,1,2,3,5,8,13..] and [0,1,1,2,3,5,8,13..], which are equivalent to 1:[1,2,3,5,8,13..] and 0:1:[1,2,3,5,8,13..] or 1:fibonacci and 0:1:fibonacci

I have looked up other ways of implementing this sequence, however I would really like to know why my code doesn't work.

like image 763
Sam Avatar asked Jun 30 '14 12:06

Sam


People also ask

Does Haskell support list comprehension?

List comprehension in Haskell is a way to produce the list of new elements from the generator we have passed inside it. Also for the generator values, we can apply the Haskell functions to modify it later. This list comprehension is very y easy to use and handle for developers and beginners as well.

How do you write Fibonacci series in python comprehension?

Write a program using list comprehension to print the Fibonacci sequence in comma separated form with a given n input by console. n=int(input()) mylist=[0,1] mylist=[mylist. append(mylist[-2]+[-1]) for n in range(n)] print(mylist).


2 Answers

The problem

With:

fibonacci = [a + b | a <- 1:fibonacci, b <- 0:1:fibonacci]

you are generating every possible combinations of the two lists. For example with:

x = [a + b | a <- [1, 2], b <- [3, 4]]

the result will be:

[1 + 3, 1 + 4, 2 + 3, 2 + 4]

Live demo

With zipWith

The closest you can get is with zipWith:

fibonacci :: [Int]
fibonacci = zipWith (+) (1:fibonacci) (0:1:fibonacci)

Live demo

like image 190
Shoe Avatar answered Jan 21 '23 03:01

Shoe


List comprehensions model

  • Non-determinism
  • Cartesian products
  • Nested for-loops

which are all equivalent. So your Fibonacci sequence is wrong because it's computing way too many elements. In pseudocode it's a bit like

fibonacci = 
  for i in 1:fibonacci:
    for j in 0:1:fibonacci:
      i + j

What you really want is to zip the lists together, to perform computations in the order of the length of fibonacci instead of its square. To do that we can use zipWith and, with a little algebra, get the standard "tricky fibo"

fibonacci = zipWith (+) (1:fibonacci) (0:1:fibonacci)
fibonacci = zipWith (+) (0:1:fibonacci) (1:fibonacci)          -- (+) is commutative
fibonacci = zipWith (+) (0:1:fibonacci) (tail (0:1:fibonacci)) -- def of tail

Then we just define

fibonacci' = 0:1:fibonacci
fibonacci' = 0:1:zipWith (+) (0:1:fibonacci) (tail (0:1:fibonacci))
fibonacci' = 0:1:zipWith (+) fibonacci' (tail fibonacci')

which is the standard with

fibonacci = drop 2 fibonacci'

You can also use the ParallelListComprehension extension which lets you do zipping in list comprehensions with a slightly different syntax

{-# ParallelListComp #-}
fibonacci = [a + b | a <- 1:fibonacci | b <- 0:1:fibonacci]

> take 10 fibonacci
[1,2,3,5,8,13,21,34,55,89]
like image 20
J. Abrahamson Avatar answered Jan 21 '23 03:01

J. Abrahamson