1

我正在尝试学习 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)))

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

任何人都可以对此有所了解吗?

4

2 回答 2

4

您遇到的问题是filter需要一个谓词(一个接受输入并返回真或假的函数)作为其第一个参数。但是 whilediv3div5是函数,您不能简单地将它们与or. 您需要构建一个新函数,该函数接受一个参数并将其提供给div3anddiv5和调用or以及两者的结果。

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

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

#()是定义内联函数(也称为lambda)的简写,您可以使用第一个参数%1到第二个参数%2,依此类推。如果只有一个论点,那么您可以使用%for%1 查看这个问题

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

于 2012-04-27T13:16:26.853 回答
3

如果您只是(or div3 div5)在 REPL 中进行评估,您可以看到正在发生的事情:

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

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

这样做的原因是or将返回它的第一个非虚假参数(即第一个不是nilor的参数false);在这种情况下,参数是两个函数对象,一个函数对象不是nilor false

换句话说,or发生在函数本身上,而不是函数的结果。正如保罗所说,您可以使用匿名函数对or结果而不是函数本身进行操作。

于 2012-04-27T13:21:37.077 回答