How does Haskell compute this enormous number instantly? - haskell

I am beginning to learn Haskell, and one of the things I like to do when I'm learning a new language is to do Project Euler problems as a supplement to my main reference material.
I have come up with the following solution to the second problem of finding the sum of the even Fibonacci numbers less than four million:
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
f :: Integer -> Integer
f n =
let evenFib = filter (\n -> n `mod` 2 == 0) fibs
in sum (takeWhile (<n) evenFib)
This works great; f 4000000 returns the correct answer. It does so instantly. Curious, I started typing in larger and larger numbers...
Prelude> f 40000000
19544084
Prelude> f 400000000000
478361013020
Prelude> f 40000000000000000000000000000000
13049874051046942401006156573274
Prelude> f 2370498572349582734598273495872349587234958723948752394857
2805750129675962215536656398462489370528480907433875715844
Each of these values is returned immediately. I have no way of guaranteeing the veracity of the last two answers, because my implementations in other languages don't work for numbers this large.
So, my question is, what is Haskell doing here? How is it returning these values instantaneously (whether they're actually correct or not)? Furthermore, are these answers indeed correct, or is Haskell just making stuff up?

It's likely nothing to do with Haskell in particular but the algorithm you're using for the other solutions.
As fibonacci numbers grow quite quickly (they get 1.6x larger on average each step), there's not that many fibonacci numbers less than 40000000000000000000000000000000, probably less than 100.
A computer adding less than 100 numbers of this size (which isn't particularly big) should take microseconds.
I'm not sure what your other implementations look like, but a common mistake is to write the Fibonacci function like this:
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
This is terrible, as fib n calls fib (n-1), which then calls fib (n-2), and returns the answer to fib n. But then you have to go an calculate fib (n-2) again because you haven't saved the answer.
A better implementation of fib in Haskell (or indeed any other language) is like the following:
fib 0 = 0
fib n = fib' 0 1 n
fib' _ curr 1 = curr
fib' last curr n = fib' curr (last+curr) (n-1)
Notice that each fib' call only makes one recursive all, not two. What I've written above is roughly what 0 : 1 : zipWith (+) fibs (tail fibs) is doing, but the above code is a bit messier but probably also easier to translate into other languages.

The answers should be correct.
You can :set +s to make ghci print memory/time information.
Running your tests again, you can see that it's actually using more and more memory:
Prelude> :set +s
Prelude> :{
Prelude| fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
Prelude| f :: Integer -> Integer
Prelude| f n =
Prelude| let evenFib = filter (\n -> n `mod` 2 == 0) fibs
Prelude| in sum (takeWhile (<n) evenFib)
Prelude| :}
(0.14 secs, 0 bytes)
Prelude> f 40000000
19544084
(0.02 secs, 83,440 bytes)
Prelude> f 40000000
19544084
(0.01 secs, 83,200 bytes)
Prelude> f 400000000000
478361013020
(0.01 secs, 94,800 bytes)
Prelude> f 40000000000000000000000000000000
13049874051046942401006156573274
(0.01 secs, 149,400 bytes)
Prelude> f 2370498572349582734598273495872349587234958723948752394857
2805750129675962215536656398462489370528480907433875715844
(0.01 secs, 225,488 bytes)
And to understand why it's so fast, take a look at the start of evenFib
Prelude> sequence_ $ map (putStrLn . show) $ take 20 $ filter ((== 0) . (flip mod 2)) $ fibs
0
2
8
34
144
610
2584
10946
46368
196418
832040
3524578
14930352
63245986
267914296
1134903170
4807526976
20365011074
86267571272
365435296162
(0.02 secs, 203,472 bytes)
The numbers are growing fast, so there really isn't much work to do.

As mentioned in the other answers it's pretty quick. While it's already quick i still have a more efficient approach relying on laziness.
For jobs like generating Fibonacci series i believe unfoldr is the ideal tool and then all we need to do is to use foldr1 to get the result. In this example foldr1 embodies the functionality of takeWhile and filter and do the same job in a single pass. So lazy unfold and fold, O(n) only.
fibs :: [Integer]
fibs = unfoldr (\(f,s) -> Just (f,(s,f+s))) (0,1)
sumEvenFibsUpto :: Integer -> Integer
sumEvenFibsUpto n = foldr1 (\ x y -> if x < n then if x `rem` 2 == 0 then x + y
else y
else 0) fibs
*Main> sumEvenFibsUpto 2370498572349582734598273495872349587234958723948752394857
2805750129675962215536656398462489370528480907433875715844
(0.01 secs, 324,392 bytes)

Related

Fibonacci numbers without using zipWith

I have been trying to implement a list of Fibonacci number sequence from 0 to n without using the lazy zipwith method. What I have so far is code that returns a list from n to 1. Is there any way I can change this code so it returns the list from 0-n at all?
Example:
fib_seq 4 = [3,2,1,1]
-- output wanted: [1,1,2,3]
If there is not a way to do what I want the code to do, is there a way to just return the list of Fibonacci numbers taking in a number say again 4 it would return [0, 1, 1, 2].
fib_seq :: Int -> [Int]
fib_seq 0 = [0]
fib_seq 1 = [1]
fib_seq n = sum (take 2 (fib_seq (n-1))) : fib_seq (n-1)
Another way you could choose to implement the fib numbers is the use of a helper function then a function on it's own that will produce the infinite list of fib numbers, or you could use take 10 fibs and the output for this would be the first 10 fib numbers. My function is definitely not the fastest way to work out the fib numbers infintely that would be with the zipWith function, but you are not using that here so here is my way to implement it without zipWith.
for example take 10 fibs would return: [0,1,1,2,3,5,8,13,21,34]
fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
fibs :: [Int]
fibs = (map fib [0..])
It is often the case that you can solve a problem by considering a slightly more general version of it.
Say we want the infinite Fibonacci list starting with two prescribed initial values a and b. There is an obvious recursive solution:
$ ghci
GHCi, version 8.8.4: https://www.haskell.org/ghc/ :? for help
...
λ>
λ> aux_fib a b = a : (aux_fib b (a+b))
λ>
λ> take 4 (aux_fib 1 1)
[1,1,2,3]
λ>
And so:
λ>
λ> fib_seq n = take n (aux_fib 1 1)
λ>
λ> fib_seq 4
[1,1,2,3]
λ>
Note: camel case is regarded as more idiomatic in Haskell, so it would be more like auxFib and fibSeq.
If you wanted to have the list start from 0 you could use a helper function and then use this helper function within your fib_seq (which i recommend you change to Camel case so like fibSeq, standard haskell notation)
Ok so the functions as follow fibSeq 7 would return [0,1,1,2,3,5,8]:
fibHelp :: Int -> Int -> [Int]
fibHelp x y = x : (fibHelp y (x+y))
fibSeq :: Int -> [Int]
fibSeq n = take n (fibHelp 0 1)
It feels a bit like cheating, but you could use the closed formula for the Fibonacci sequence like this:
fib n = (phi^n - psi^n) / sqrt 5
where
phi = (1 + sqrt 5) / 2
psi = (1 - sqrt 5) / 2
fibSeq n = fib <$> [1 .. n]
Otherwise the Haskell Wiki has many more implementation variants to chose from. For example very succinctly
fibs = 0 : 1 : next fibs
where
next (a : t#(b:_)) = (a+b) : next t

Fibonacci Bit Representation Haskell

I already have the following functions
toBin, auxBin :: Integer -> [Integer]
toBin 0 = [0]
toBin n = reverse (auxBin n)
auxBin 0 = []
auxBin n = n `mod` 2 : auxBin (n `div` 2)
fib :: Int -> Integer
fib n = fibs !! n
where
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
fibonacci = [fib n | n <- [0..]]
But when I map the Fibonacci list with the toBin function, I obtained an incorrect list:
Becuase, I obtained this:
[[0],[1],[1],[1,0],[1,1],[1,0,1],[1,0,0,0],[1,1,0,1],[1,0,1,0,1],[1,0,0,0,1,0]]
But, I want this:
[0,1,10,101,1010,10101,101010,1010101,10101010,101010101]
Could you help me?
There are many ways to add digits together in order to get a number. Here's one way. Probably not the most efficient way, but on the other hand built up from smaller functions.
Values like [1,0,1],[1,0,0,0], and [1,1,0,1] are lists in their own right, so what we can do first is to index them. The only trouble is that we'd like to index them in descending order. You can do that by reversing them, indexing them, and then reverse them again, e.g.:
Prelude> reverse $ zip [0..] $ reverse [1,1,0,1]
[(3,1),(2,1),(1,0),(0,1)]
The first element in each tuple is the order of magnitude, so you just need to make it a power of ten:
Prelude> :m +Data.Bifunctor
Prelude Data.Bifunctor> reverse $ fmap (first (10 ^)) $ zip [0..] $ reverse [1,1,0,1]
[(1000,1),(100,1),(10,0),(1,1)]
Now you can simply multiply the elements of the tuples together:
Prelude Data.Bifunctor> reverse $ fmap (uncurry (*) . first (10 ^)) $ zip [0..] $ reverse [1,1,0,1]
[1000,100,0,1]
Finally, you can add all of those numbers together. In fact, you don't need to reverse the reversed list:
Prelude Data.Bifunctor> sum $ fmap (uncurry (*) . first (10 ^)) $ zip [0..] $ reverse [1,1,0,1]
1101
You can put such a combination in a function and map your values over it.
A more efficient solution would probably be to just be to do a left fold (foldl), e.g.:
Prelude> foldl (\acc x -> (10 * acc) + x) 0 [1,1,0,1]
1101
Prelude> foldl (\acc x -> (10 * acc) + x) 0 [1,1,1]
111
An idea could be to represent binary values in decimal notation. So we "transform" 2 into 10.
We can do that by writing a recursive function:
bintodec :: Integral i => i -> i
bintodec 0 = 0
bintodec i = (mod i 2) + 10 * bintodec (div i 2)
This only works for positive values, but that is not really a problem here, since Fibonacci numbers are positive numbers.
Now we already have a definition of the Fibonacci numbers, like in your answer:
fibs :: Num n => [n]
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
So the only thing we still have to do is map every elements of fibs with bintodec:
binfibs :: Integral i => [i]
binfibs = map bintodec fibs
The first 15 numbers are then:
Prelude> take 15 binfibs
[0,1,1,10,11,101,1000,1101,10101,100010,110111,1011001,10010000,11101001,101111001]
The nice thing is here that we do not use any binary lists to process it, but keep working in the integer world, which is usually more safe.
Based on the second list however, this has nothing to do with Fibonacci numbers. There you start with 0, and you then shift a zero or a one in at the right end of the number.
We can use iterate for this:
iterate (\x -> 10 * x + 1-(mod x 2)) 0
which produces:
Prelude> take 15 $ iterate (\x -> 10 * x + 1-(mod x 2)) 0
[0,1,10,101,1010,10101,101010,1010101,10101010,101010101,1010101010,10101010101,101010101010,1010101010101,10101010101010]

Haskell: Why is my implementation of the Fibonacci sequence inefficient?

I have written the following Fibonacci play program as part of learning Haskell:
fibonacci 0 = [0]
fibonacci 1 = [0,1]
fibonacci n = let
foo'1 = last (fibonacci (n-1))
foo'2 = last (fibonacci (n-2))
in reverse((foo'1 + foo'2):reverse (fibonacci (n-1)))
The program works:
ghci>fibonacci 6
[0,1,1,2,3,5,8]
But, the performance goes down exponentially with n. If I give it an argument of 30 it takes about a minute to run as opposed to running instantaneously at 6. It seems the lazy execution is burning me and fibonacci is getting run once for every element in the final list.
Am I doing something silly or missing something?
(I already got rid of the ++ thinking that might be doing it)
As pointed out in the comments, your approach is a tad overcomplicated. In particular, you don't need to use recursive calls, or even the reverse function, in order to generate the Fibonacci sequence.
A linear-time implementation
In addition to your own answer, here is a textbook one-liner, which uses memoization:
fibs :: [Integer]
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
Once you have fibs, writing your fib function is trivial:
fib :: Int -> [Integer]
fib n
| n < 0 = error "fib: negative argument"
| otherwise = take (n+1) fibs
This implementation of fib has complexity Θ(n), which is obviously much better than Θ(exp(n)).
Test in GHCi
λ> :set +s
λ> fib 6
[0,1,1,2,3,5,8]
(0.02 secs, 7282592 bytes)
λ> fib 30
[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040]
(0.01 secs, 1035344 bytes)
As you can see, fib 30 is evaluated in well under one minute on my machine.
Further reading
For a much more comprehensive treatment of how to generate the Fibonacci sequence in Haskell, I refer you to this haskell.org wiki
Here is the answer to the question using #icktoofay's pointer to memoization. The answer included a function that quickly returned a given fibonacci number, so I used their example to create a solution to my original problem--creating a list of the Fibonacci numbers up to the requested number.
This solution runs pretty much instantaneously (the page has the additional benefit of referring to my approach as "naive")
memoized_fib :: Int -> Integer
memoized_fib = (map fib [0 ..] !!)
where fib 0 = 0
fib 1 = 1
fib n = memoized_fib (n-2) + memoized_fib (n-1)
fib 0 = [0]
fib 1 = [0,1]
fib n = reverse ((memoized_fib (n-2) + memoized_fib(n-1)) : reverse (fib (n-1)))
You don't need to add memoization to your function - it already has all the previous results, producing a list as it does. You just need to stop ignoring those results, as you do right now using last.
First of all, if it's more natural to build the list in reverse order, there's no reason not to:
revFib 0 = [0]
revFib 1 = [1,0]
revFib n | n > 0 = let f1 = head (revFib (n-1))
f2 = head (revFib (n-2))
in f1 + f2 : revFib (n-1)
This is still slow, as we're still ignoring all the previous results except the very last one, situated at the head of the list. We can stop doing that,
revFib 0 = [0]
revFib 1 = [1,0]
revFib n | n > 0 = let f1 = head (revFib (n-1))
f2 = head (tail (revFib (n-1)))
in f1 + f2 : revFib (n-1)
and then we'll name the common subexpression, so that it is shared among its uses, and is only calculated once:
revFib 0 = [0]
revFib 1 = [1,0]
revFib n | n > 0 = let prevs = revFib (n-1)
[f1,f2] = take 2 prevs
in f1 + f2 : prevs
and suddenly it's linear instead of exponential.

Infinitely lazy factorial in Haskell

In a similar fashion as the Fibonacci series may be generated as follows,
fibs :: [Integer]
fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
how to define the series for factorial.
Update
Embarrassingly enough, tried this quite before adding this question,
Prelude> let factorial = 2 : 6 : zipWith(*) factorial (tail factorial)
Prelude> take 5 factorial
[2,6,12,72,864]
Indeed the numbers in the tail are not successive values, to start with.
Lets take a step back and remember where that lazy version actually comes from:
fib 0 = 1
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
We can also define the factorial similarly:
factorial 0 = 1
factorial n = factorial (n - 1) * n
As you can see, our zipping operation is actually (*), and the second list won't be a sublist of factorials, but instead [x..] with an appropriate x:
factorials = 1 : zipWith (*) factorials [x..]
What value should x be? Well, the second element should be 1 = 1 * 1, so it's 1, naturally:
factorials = 1 : zipWith (*) factorials [1..]
Note that we only need to give the first element, since we don't use tail or something similar. As you can see, your attempt was almost correct. You just used the wrong values for the left hand side:
Prelude> let factorial = 2 : 6 : zipWith (*) [4..] (tail factorial)
Prelude> take 10 $ factorial
[2,6,24,120,720,5040,40320,362880,3628800,39916800]
Remark: The factorial sequence is 0!, 1!, 2!, ..., so if you want to be OEIS compliant start with [1,1,...].
The idiomatic definition of a lazy list of factorials is not recursive at all: instead it uses the Prelude function scanl.
factorials = scanl (*) 1 [1..]
Given the usual definition of factorial:
factorial :: Integer -> Integer
factorial 0 = 1
factorial i = foldr (*) 1 [2..i]
we can generate an infinite list of all factorials by simply running the factorial function over an infinite list of all positive numbers:
inFact :: [Integer]
inFact = map factorial [0..]
Live demo

Setting upper limit to the input set according to the output function

I'm currently stuck on setting upper limits in list comprehensions.
What I'm trying to do is to find all Fibonacci numbers below one million.
For this I had designed a rather simple recursive Fibonacci function
fib :: Int -> Integer
fib n
n == 0 = 0
n == 1 = 1
otherwise = fib (n-1) + fib (n-2)
The thing where I'm stuck on is defining the one million part. What I've got now is:
[ fib x | x <- [0..35], fib x < 1000000 ]
This because I know that the 35th number in the Fibonacci sequence is a high enough number.
However, what I'd like to have is to find that limit via a function and set it that way.
[ fib x | x <- [0..], fib x < 1000000 ]
This does give me the numbers, but it simply doesn't stop. It results in Haskell trying to find Fibonacci numbers below one million further in the sequence, which is rather fruitless.
Could anyone help me out with this? It'd be much appreciated!
The check fib x < 1000000 in the list comprehension filters away the fib x values that are less than 1000000; but the list comprehension has no way of knowing that greater values of x imply greater value of fib x and hence must continue until all x have been checked.
Use takeWhile instead:
takeWhile (< 1000000) [ fib x | x <- [0..35]]
A list comprehension is guaranteed to look at every element of the list. You want takeWhile :: (a -> Bool) -> [a] -> [a]. With it, your list is simply takeWhile (< 1000000) $ map fib [1..]. The takeWhile function simply returns the leading portion of the list which satisfies the given predicate; there's also a similar dropWhile function which drops the leading portion of the list which satisfies the given predicate, as well as span :: (a -> Bool) -> [a] -> ([a], [a]), which is just (takeWhile p xs, dropWhile p xs), and the similar break, which breaks the list in two when the predicate is true (and is equivalent to span (not . p). Thus, for instance:
takeWhile (< 3) [1,2,3,4,5,4,3,2,1] == [1,2]
dropWhile (< 3) [1,2,3,4,5,4,3,2,1] == [3,4,5,4,3,2,1]
span (< 3) [1,2,3,4,5,4,3,2,1] == ([1,2],[3,4,5,4,3,2,1])
break (> 3) [1,2,3,4,5,4,3,2,1] == ([1,2,3],[4,5,4,3,2,1])
It should be mentioned that for such a task the "canonical" (and faster) way is to define the numbers as an infinite stream, e.g.
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
takeWhile (<100) fibs
--[0,1,1,2,3,5,8,13,21,34,55,89]
The recursive definition may look scary (or even "magic") at first, but if you "think lazy", it will make sense.
A "loopy" (and in a sense more "imperative") way to define such an infinite list is:
fibs = map fst $ iterate (\(a,b) -> (b,a+b)) (0,1)
[Edit]
For an efficient direct calculation (without infinite list) you can use matrix multiplication:
fib n = second $ (0,1,1,1) ** n where
p ** 0 = (1,0,0,1)
p ** 1 = p
p ** n | even n = (p `x` p) ** (n `div` 2)
| otherwise = p `x` (p ** (n-1))
(a,b,c,d) `x` (q,r,s,t) = (a*q+b*s, a*r+b*t,c*q+d*s,c*r+d*t)
second (_,f,_,_) = f
(That was really fun to write, but I'm always grateful for suggestions)
The simplest thing I can think of is:
[ fib x | x <- [1..1000000] ]
Since fib n > n for all n > 3.

Resources