Clojure - 总结一堆数字

标签 clojure lisp

嘿,我正在做一个欧拉计划问题,我想求和所有小于 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/

相关文章:

clojure - pprint 符号已指用户

clojure - 什么时候应该使用交换或重置

lisp - 如何使用任意数量的参数在 lisp 中定义结构?

parallel-processing - 为并行执行重写顺序代码

lisp - (方案)递归函数来计算某些列表的所有可能组合?

clojure - 用于无 UI 网络服务的 Compojure 或 Noir?

Clojure::互相调用的Arity重载函数

function - 为什么许多 lisp 函数名称都像 "foo"、 "foo-1"、 "foo-2"等?

Clojure:为什么 if-let 只允许绑定(bind)向量中有 2 种形式?

c - 启用宏的语言如何跟踪源代码以进行调试?