1

Problem 2 of Project Euler says: Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.

GHCi parses this solution just fine:

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
p002fibsum x = sum (filter even (takeWhile (< (x+1)) fibs))

...but it has a problem with this one:

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
p002fibsum x = sum . filter even . takeWhile (< (x+1)) fibs

Couldn't match expected type `a1 -> [c0]' with actual type `[a0]'
In the return type of a call of `takeWhile'
Probable cause: `takeWhile' is applied to too many arguments
In the second argument of `(.)', namely
  `takeWhile (< (x + 1)) fibs'
In the second argument of `(.)', namely
  `filter even . takeWhile (< (x + 1)) fibs'

takeWhile seems to take only two params, which seem to be the right amount. Am I failing because of a missing type signature? How can I get this solution to work with dot notation?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Mark Karavan
  • 2,654
  • 1
  • 18
  • 38
  • 1
    Try `sum . filter even . takeWhile (< (x + 1)) $ fibs`. The problem is that you're trying to compose `filter even` and `takeWhile (< (x + 1)) fibs`, but the latter isn't a function, hence the error saying it can't match `[a]` with `b -> [c]`. The `$` operator basically forces evaluation of both sides before apply the left as a function to the right. Alternatively, you could do `sum $ filter even $ takeWhile (< (x + 1)) fibs`. – bheklilr Jan 19 '15 at 23:17
  • 1
    By doing `sum . filter even . takeWhile (< (x + 1))`, you're creating a new function to apply to `fibs` using `$`. It all comes down to operator precedence, like how `2 * x + 1` is interpreted as `(2 * x) + 1` rather than `2 * (x + 1)` since `*` has higher precedence than `+`. The `$` operator has very low precedence, lower than `.`, but function application (e.g. `takeWhile (< (x + 1)) fibs` has higher precedence than anything else. – bheklilr Jan 19 '15 at 23:20
  • So is the (.) operator not typically used with expressions that have parameters in them? It seems like it is only used to compose functions, regardless of their parameters. – Mark Karavan Jan 19 '15 at 23:37
  • 1
    the composition operator is typically used with functions that only have one argument not yet supplied. You can use it when the function has parameters, but you have to make sure it still has a parameter that has yet to be supplied. – bheklilr Jan 19 '15 at 23:40

1 Answers1

1

The problem is that takeWhile (< (x+1)) fibs has the type [a0] (where a0 is some Num), while the function composition expects a function for its second argument (a1 -> [c0]).

If you want to use dot notation, it would be

p002fibsum x = (sum . filter even . takeWhile (< (x+1))) fibs

though I'd rather use dollar signs:

p002fibsum x = sum $ filter even $ takeWhile (< (x+1)) fibs
Bergi
  • 630,263
  • 148
  • 957
  • 1,375