Macros 如何使用clojure for loop宏查找n个数的和?

Macros 如何使用clojure for loop宏查找n个数的和?,macros,clojure,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; 用于(

我在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;
用于(int i=1;i
(定义和(原子0))
(def n 100)
(对于循环[i0(
首先,这里不需要使用宏。其次,在最后调用
recur
时使用
do
,将防止宏返回除nil以外的值,正如Lee的回答中所讨论的。当你没有真正提供
else时,你应该使用
而不是
if
大小写只是一个小问题,但它暗示了一个可能更好的解决方案:使用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)
(对于循环[i0r0(
如果展开此宏,则更容易看到正在进行的操作:

 (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))
(pprint(macroexpand-1'(用于循环[i0r0((clojure.core/loop[i 0 r 0]
(如果(

如果不必显式地命名和使用累加器,而只需使用
步骤的结果,那就太好了,但是在本例中,这些步骤可能需要引用任何中间值,因此无法绕过它。

拥有一个变量并更新其值不是惯用的clojure,您需要可能需要类似于
(reduce+(range(inc n)))
的东西。但是,这种情况在不使用for循环宏的情况下发生。是否仍要使用for循环宏?我正在尝试学习宏,因此提出了一个问题。“学习宏”是指“学习编写宏”还是“学习使用宏”?因为后者不需要那么多专业知识(尽管有些文档)这肯定是前一个的先决条件。嗨@Lee,它给出了一个nil值。@MarthaPears-是的,循环的计算结果为nil,但
@sum
包含了这个和。循环只是为了它的效果而执行的。使用外部原子确实不是惯用的。@schaueho-除非我遗漏了什么,否则
for loop
宏总是计算结果如果要使用外部状态来计算值,则必须使用外部状态。是的,我同意,如果坚持使用提供的精确的
for loop
宏,这可能是唯一的方法。
 (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))