Clojure - 总结了一堆数字

Lyn*_*Dev 4 lisp clojure

嘿,我正在做一个项目欧拉问题,我想要总结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)
Run Code Online (Sandbox Code Playgroud)

线路(swap! result (+ @result i)))也让result += i我感到烦恼..在C#我能做到,但我猜在Clojure中必须有更好的方法吗?

leo*_*ges 15

在Clojure中 - 在函数式编程中 - 我们避免了赋值,因为它破坏了状态历史并使编写并发程序变得更加困难.事实上,Clojure甚至不支持任务.An atom是一种线程安全的引用类型.

函数式编程的另一个共同特点是我们尝试将问题解决为一系列数据转换.在您的情况下,您可以使用一些数据,0到1000的数字列表,并且您需要获取与谓词匹配的所有数字的总和.这当然可以通过应用数据转换并完全消除分配的需要来完成.一个这样的实现是这样的:

(->> (range 1000)
     (filter #(or (= (rem % 3) 0) (= (rem % 5) 0)))
     (reduce +))
Run Code Online (Sandbox Code Playgroud)

请理解,您编写的功能不被视为惯用代码.话虽如此,为了学习,它可以像这样工作:

(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)
Run Code Online (Sandbox Code Playgroud)

for返回一个懒惰的序列,但因为你只是对swap!你需要使用doseq强制序列引起的副作用感兴趣.另一个问题是第二个参数swap!是一个函数,所以你不需要result再次deref .

  • `(swap!result#(+%i))`是`(swap!result + i)` (3认同)

omi*_*iel 5

for 是一个返回惰性序列的列表理解,你必须遍历它才能使你的代码工作:

(defn sum-of-multiples [max]
  (let [result (atom 0)]
    (dorun
      (for [i (range max)] 
        (if (or (= (rem i 3) 0) (= (rem i 5) 0))
          (swap! result + i))))
    @result))
Run Code Online (Sandbox Code Playgroud)

使用以下内容的等效,更惯用的实现for:

(defn sum-of-multiples [max]
  (reduce +
    (for [i (range max)
          :when (or (zero? (rem i 3))
                    (zero? (rem i 5)))] 
      i)))
Run Code Online (Sandbox Code Playgroud)