嘿,我正在做一个欧拉计划问题,我想求和所有小于 1000 的数字,它们是 3 或 5 的倍数。
但是作为一个 clojure 菜鸟,我的代码总是返回零……我不确定为什么。
(defn sum-of-multiples [max]
(let [result (atom 0)]
(for [i (range max)]
(if (or (= (rem i 3) 0) (= (rem i 5) 0))
(swap! result (+ @result i)))
)
@result))
(sum-of-multiples 1000)
(swap!result (+ @result i)))
这行也让我感到困惑。在 C# 中我可以做 result += i
,但我猜想在 Clojure 中一定有更好的方法吗?
最佳答案
在 Clojure 中——以及整个函数式编程中——我们避免赋值,因为它会破坏状态历史并使编写并发程序变得更加困难。事实上,Clojure 甚至不支持赋值。 atom
是线程安全的引用类型。
函数式编程的另一个共同特征是我们尝试将问题作为一系列数据转换来解决。在您的情况下,您需要一些数据,一个从 0 到 1000 的数字列表,并且您需要获得与谓词匹配的所有数字的总和。这当然可以通过应用数据转换并完全消除分配需求来完成。一个这样的实现是这样的:
(->> (range 1000)
(filter #(or (= (rem % 3) 0) (= (rem % 5) 0)))
(reduce +))
请理解,诸如您编写的函数之类的函数不被视为惯用代码。话虽如此,为了学习的兴趣,它可以像这样工作:
(defn sum-of-multiples [max]
(let [result (atom 0)]
(doseq [i (range max)]
(if (or (= (rem i 3) 0) (= (rem i 5) 0))
(swap! result #(+ % i)))
)
@result))
(sum-of-multiples 1000)
for
返回惰性序列,但由于您只是对 swap!
引起的副作用感兴趣,因此您需要使用 doseq
强制顺序。另一个问题是 swap!
的第二个参数是一个函数,因此您不需要再次取消引用 result
。
关于Clojure - 总结一堆数字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24576431/