注意:不是重复为什么Clojure重复认为它应该只有一个参数?.我没有使用循环.
(def t
#(let [[low high] (sort %&)] {:low low :high h}))
(t 3 2)
=> {:low 2, :high 3}
Run Code Online (Sandbox Code Playgroud)
鉴于这是按预期工作的.怎么没有:
(def t
#(let [[low high] (sort %&)]
(if (= 0 low)
nil
(do
(println {:low low :high high})
(recur low (dec high))))))
(t 3 2)
=> java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 2
Run Code Online (Sandbox Code Playgroud)
鉴于它说它期待1个参数我可以猜测我可以通过将参数转换为集合来使其工作:
(def t
#(let [[low high] (sort %&)]
(if (= 0 low)
nil
(do
(println {:low low :high high})
(recur [low (dec high)])))))
(t 3 2)
=> {:low 2, :high 3}
{:low 2, :high 2}
{:low 1, :high 2}
{:low 1, :high 1}
nil
Run Code Online (Sandbox Code Playgroud)
... 但为什么?
这就是它的设计方式.在Clojure的网站说:
recur表达式必须与递归点的arity完全匹配.特别是,如果递归点是可变参数fn方法的顶部,则不会收集休息参数 - 应该传递单个seq(或null).
我认为它是以这种方式设计的,因为如果函数本身给你一个序列(而不是单独的参数),那么重复形式更自然地接受序列,或者可以成为序列的东西.如果不是这种情况,则需要拆分给定的序列以执行递归.
你的例子似乎不适合模具,因为看起来你真的只关心有两个参数,这意味着你真的不需要其余的参数.你可能最好明确定义两个参数并确定let语句中哪个低和高,而不是对其余的args进行排序并对它们进行解构.
这是您的代码,只需要很少的修改.我将两个显式参数包装在一个向量中,然后将它们传递给sort(基本上模仿rest args),并将两个参数传递给recur.
(def t
#(let [[low high] (sort [%1 %2])]
(if (= 0 low)
nil
(do
(println {:low low :high high})
(recur low (dec high))))))
Run Code Online (Sandbox Code Playgroud)
但是,在保持重复形式的同时,我可能会稍微重构一下:
(defn t [x y]
(let [low (min x y) high (max x y)]
(when-not (zero? low)
(println {:low low :high high})
(recur low (dec high)))))
Run Code Online (Sandbox Code Playgroud)