如何使用clojure for loop macro找到n个数的和?

时间:2014-10-28 14:42:22

标签: macros clojure

我在clojure中使用for循环宏:

 (defmacro for-loop [[sym initial check-exp post-exp] & steps]
 `(loop [~sym ~initial]
    (if ~check-exp
      (do
        ~@steps
        (recur ~post-exp)))))

我想写一个简单的函数来查找n个数字的总和,如:

for(int i=1; i<n; i++)
sum=sum+i;

如何使用for-loop宏在clojure中执行此操作?

2 个答案:

答案 0 :(得分:1)

首先,这里不需要使用宏。其次,在do的最终调用中使用recur将阻止宏返回除了nil之外的值,如Lee的回答中所述。如果您没有真正提供when案例,则应该使用if代替else只是一个小问题,但暗示可能更好的解决方案:使用else案例返回结果。为此,您需要在等式中引入累加器。

(defmacro for-loop [[sym initial result initial-result check-exp post-exp] & steps]
 `(loop [~sym ~initial
         ~result ~initial-result]
    (if ~check-exp
      (do
        ~@steps
        (recur ~@post-exp))
      ~result)))

这仍然非常难看,但允许你像这样解决你的求和任务,实际上不需要任何中间步骤:

 (for-loop [i 0 r 0 (< i n) ((inc i) (+ r i))] nil)

如果您对此进行宏观扩展,则会更容易看到:

 (pprint (macroexpand-1 '(for-loop [i 0 r 0 (< i n) ((inc i) (+ r i))] nil)))
 ==> (clojure.core/loop [i 0 r 0]
       (if (< i n) 
           (do nil 
               (recur (inc i) (+ r i))) 
           r))

如果不必显式地命名和使用累加器但只使用steps的结果,那将是很好的,但是因为步骤可能需要引用任何中间值构建到目前为止在这个例子中,没有办法绕过它。

答案 1 :(得分:0)

(def sum (atom 0))
(def n 100)

(for-loop [i 0 (< i n) (inc i)] (swap! sum #(+ % i)))