1

I am learning Clojure and trying to solve Project's Euler (http://projecteuler.net/) problems using this language. Second problem asks to find the sum of the even-valued terms in Fibonacci sequence whose values do not exceed four million.

I've tried several approaches and would find next one most accurate if I could find where it's broken. Now it returns 0. I am pretty sure there is a problem with take-while condition but can't figure it out.

(reduce + 
  (take-while (and even? (partial < 4000000))  
    (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))))
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Shkarik
  • 1,139
  • 2
  • 9
  • 17

2 Answers2

10

To compose multiple predicates in this way, you can use every-pred:

(every-pred even? (partial > 4000000))

The return value of this expression is a function that takes an argument and returns true if it is both even and greater than 4000000, false otherwise.

Michał Marczyk
  • 83,634
  • 13
  • 201
  • 212
  • Why do I get 0 for this code then? (take-while (every-pred even? (partial > 100)) (range)) – Shkarik Dec 30 '13 at 23:37
  • 2
    You get a sequence `'(0)`, because `take-while` stops consuming as soon as the predicate returns a non true value. It will return true for 0 (being even and smaller than 100), but false for 1 because it's not even. So you may want to use `filter` instead. – Leon Grapenthin Dec 30 '13 at 23:43
  • I think you mean (partial < 4000000), based on your verbal description of the function. – noisesmith Dec 31 '13 at 00:38
  • user> (map (partial < 4000000) [0 Integer/MAX_VALUE]) => (false true) – noisesmith Dec 31 '13 at 00:41
6
user> ((partial < 4000000) 1) 
false 

Partial puts the static arguments first and the free ones at the end, so it's building the opposite of what you want. It is essentially producing #(< 4000000 %) instead of #(< % 4000000) as you intended, So just change the > to <:

user> (reduce +
        (take-while (and even? (partial > 4000000))
                         (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))))
9227464

or perhaps it would be more clear to use the anonymous function form directly:

user> (reduce +
              (take-while (and even? #(< % 4000000))
                          (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))))
9227464 

Now that we have covered a bit about partial, let's break down a working solution. I'll use the thread-last macro ->> to show each step separately.

user> (->> (iterate (fn [[a b]] [b (+ a b)]) [0 1]) ;; start with the fibs
           (map first)                              ;; keep only the answer   
           (take-while #(< % 4000000))              ;; stop when they get too big
           (filter even?)                           ;; take only the even? ones
           (reduce +))                              ;; sum it all together.
4613732

From this we can see that we don't actually want to compose the predicates evan? and less-than-4000000 on a take-while because this would stop as soon as either condition was true leaving only the number zero. Rather we want to use one of the predicates as a limit and the other as a filter.

Arthur Ulfeldt
  • 90,827
  • 27
  • 201
  • 284
  • Cool. Thanks for explanation! Now I've got another problem - for some reason the result (9227464) is twice as many as real solution (4613732). How has it doubled? – Shkarik Dec 30 '13 at 22:51
  • 5
    That's because `(and even? (partial > 4000000))` returns `(partial > 4000000)` -- it's *not* composing the two predicates in any sense, but rather computing the logical "and" of `even?` and `(partial > 4000000)`. These are neither `false` nor `nil`, so they're both truthy, so the last one of them will be returned. Ultimately only `(partial > 4000000)` ends up being used by `take-while`. – Michał Marczyk Dec 30 '13 at 22:59