Clojure需要合理的逻辑和

时间:2013-12-30 22:28:06

标签: clojure predicates

我正在学习Clojure并尝试使用这种语言解决Project的Euler(http://projecteuler.net/)问题。 第二个问题要求找到Fibonacci序列中偶数值的总和,其值不超过四百万。

我已经尝试了几种方法,如果我能找到它破碎的地方,我会发现下一种方法最准确。现在它返回0.我很确定暂停条件存在问题,但无法弄明白。

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

2 个答案:

答案 0 :(得分:10)

要以这种方式撰写多个谓词,您可以使用every-pred

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

此表达式的返回值是一个接受参数的函数,如果它是偶数且大于4000000则返回true,否则返回false

答案 1 :(得分:6)

user> ((partial < 4000000) 1) 
false 

Partial将静态参数放在第一位,将自由参数放在最后,这样就构建了与你想要的相反的方式。它实际上是按照您的意图生成#(< 4000000 %)而不是#(< % 4000000),所以只需将>更改为<

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

或者可能更直接地使用匿名函数形式:

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

现在我们已经介绍了部分内容,让我们分解一个有效的解决方案。我将使用线程最后一个宏->>分别显示每个步骤。

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

由此我们可以看到我们实际上并不想在evan?上撰写谓词 take-while和小于4000000,因为这会很快停止因为任何条件都是真的,只留下数字零。相反,我们希望使用其中一个谓词作为限制而另一个作为过滤器。