Clojure:过滤器如何与逻辑交互?

时间:2012-04-27 13:13:32

标签: clojure

我正在努力学习Clojure,所以我认为开始的一个好方法是使用它来完成Euler项目的挑战,第一个挑战是将1000以下的所有数字相加,可以被3或5整除

我原来的代码是:

(defn div3 [input-no] (zero? (mod input-no 3)))
(defn div5 [input-no] (zero? (mod input-no 5)))
(reduce + (filter (or div3 div5) (range 1 1000)))

但是这没有用,结果是过滤器只返回一个可被3整除的数字列表,而不是那些被5整除的数字。

我将代码更改为:

(defn div3or5 [input-no] (or (div3 input-no) (div5 input-no)))
(reduce + (filter div3or5 (range 1 1000)))

哪个得到了正确的结果,但我不知道为什么我的原始代码不起作用。

有人可以对此有所了解吗?

2 个答案:

答案 0 :(得分:4)

您遇到的问题是filter期望谓词(一个输入并返回true或false的函数)作为其第一个参数。但是,虽然div3div5是函数,但您不能简单地将它们与or结合使用。您需要构造一个新函数,该函数接受一个参数并将其提供给div3div5,并调用or和两者的结果。

幸运的是,在Clojure中这很容易做到,试试

(filter #(or (div3 %) (div5 %)) (range1 1000))

#()是定义函数内联的简写(也称为 lambda ),你可以使用%1到第二个%2的第一个参数} 等等。如果只有一个参数,那么您可以%使用%1 see this question

您可能还想了解#()只是fn形式的语法糖 看起来像这样:(fn [arg1 arg2 ... & restArgs] (forms))#()有一些限制(例如,它不能嵌套)。

答案 1 :(得分:3)

如果您只是评估REPL中的(or div3 div5),您可以看到发生了什么:

=> (or div3 div5)
#<user$div3 user$div3@73305c>

也就是说,or正在评估函数div3filter正在使用它,给出您描述的行为。)

原因是or将返回其第一个非虚假参数(即第一个参数不是nilfalse);在这种情况下,参数是两个函数对象,函数对象不是nilfalse

换句话说,or发生在函数本身,而不是函数的结果。正如Paul所说,你可以使用匿名函数使or对结果而不是函数本身起作用。