Some room for improvement:
This is more of a preference, but I find this style more readable. What do you think?
fibonacci n | n == 1 || n == 2 = n
| n >= 3 = fibonacci (n - 1) + fibonacci (n - 2)
| otherwise = 0
-- Intermediate code: list of first 32 Fibonacci numbers
fibonacciList = [fibonacci i | i <- [1..32]]
I like what you are doing here, but I feel like you are doing too much work. It seems to me that what you actually wanted to do here is to generate a list numbers from 1 to 32, but you want to transform (map) those numbers from simple integers to corresponding Fibonacci number. Well I think you got my hint there, the function you are looking for is called map.
What does map do? Well let's first look at the signature for map
Prelude> :t map
map :: (a -> b) -> [a] -> [b]
What this says is that map takes a function going from
a => b as it's first parameter, followed by a list of type
a, then it returns a list of type
b. This is exactly what you need. You already have a function that takes simple meager integers and transforms them into fibonacci numbers, and you have a list of integers, so all that is needed now is to call map with these inputs and have it do the work. So here goes
map fib [1..32]
-- list of even Fibonacci numbers from fibonacciList
evenFibonacci = [eF | eF <- fibonacciList, eF `mod` 2 == 0]
Here we have another common haskell gem not being recognized for what it's worth. It looks like what you want to do here is to scrutinize a list and take only (filter) the even values from such a list. Again I left just there another hint. The Haskel gem you seek is called filter and here is the signature:
Prelude> :t filter
filter :: (a -> Bool) -> [a] -> [a]
How do we interpret this? Simple, filter is a function that takes a function which goes from
a => Bool and a list of type
a, then it returns another list of the same type.
How is this different from map? Notice that firstly the first parameter of map is a function that returns a generic type, however in the case of filter, the first parameter always returns
Bool. Moreover, something that may not yet be obvious is that the length of the list returned by map is always equal to the length of the original list given to it, but this is not always true for filter.
Anyways, let us replace that function you have, with filter:
filter (\f -> f `mod` 2 == 0)
And now for the list to give to filter, we can reuse the original map solution to fix this
filter (\f -> f `mod` 2 == 0) $ map fib [1..32]
Even Fibonacci 2
The second evenFibonacci method you have is doing something else that is not immediately obvious. I think I understand what you wanted to do there being that you want to take only the first fibonacci numbers whose value does not exceed 4,000,000. However, you are still using what I would still consider a filter. The problem with your filter currently is that it does not ever stop filtering, so even if your fibonacci numbers are larger than 4,000,000, the filter will continue to filter but everything will return false. Lucky for you, haskell is lazy in that you can pretty much stop-the-world if things get too out of hand so you never get to see the effect of this, however imagine if you had an infinite list and needed this computation to stop once the values get large.
Ok let me introduce takeWhile, with the signature:
Prelude> :t takeWhile
takeWhile :: (a -> Bool) -> [a] -> [a]
I know it looks a lot like filter, but the distinction is in the name (if you are an English speaker) or the use once you read the documentation. takeWhile differs from filter in that once the function (first arguement) returns false, takeWhile quits. This is exactly what you need here to ensure that once the numbers start getting larger than 4,000,000 your function does not continue to evaluate more values.
So let's implement this:
takeWhile (< 4000000)
Combining with the previous 2, we have,
filter (\f -> f `mod` 2 == 0) $ takeWhile (< 4000000) $ map fib [1..32]
Yea, I skipped
sumEvenFibonacci because that one is ok..for now. What is wrong with main? Well nothing really except that it is too short. There is no build up, no suspense, nothing!.
Let's change that.
main can actually be changed to compose everything we already have. The goal of this program is to
- generate a list of fibonacci numbers
- take only the first few that do not exceed 4,000,000
- filter those ones to include only the even ones
- sum them all together
- and finally print the value.
So like I said, let us compose main to look just the way I described it. To compose functions in haskell, you have to make use of the
. (composition function). So starting from the bottom, let's go:
main :: IO()
main = print . sum . filter (\f -> f `mod` 2 == 0) . takeWhile (< 4000000) . map fib $ [1..32]
And voila! Happy days.
I hope you took note of how our numbered list
1-5 was applied in reverse. This captures the essence of programming in purely functional languages like haskell vs something like C++. In procedural languages, if you say you want to do something, you start from step 1, and carry along to step
End. The opposite is true in functional programming.