我如何展平传递给 recur 的参数?

Oin*_*Oin 1 loops clojure

我正在尝试了解loop/recur. 我想将函数的返回向量传递回循环,我尝试过这样的事情:

(defn foo [x y] 
  [(dec x) y])

(loop [x 3 y 4]
  (if (> x 0)
    (do
      (prn x y)
      (recur (foo x y)))))
Run Code Online (Sandbox Code Playgroud)

这给出了:

1. Caused by java.lang.IllegalArgumentException
   Mismatched argument count to recur, expected: 2 args, got: 1
Run Code Online (Sandbox Code Playgroud)

现在我可以将循环参数更改为另一种有效的形式:

(defn foo [x y] 
  [(dec x) y])

(loop [[x y] [3 4]]
  (if (> x 0)
    (do
      (prn x y)
      (recur (foo x y)))))
Run Code Online (Sandbox Code Playgroud)

我想知道是否有任何方法可以更改第一个代码以离开(loop [x 3 y 4] ...)但更改以recur某种方式传递给的参数。我想我需要类似apply函数的东西,但我无法使用它recur,因为recur它不是函数。

cfr*_*ick 6

没有简单的方法可以解决。 recur是一种特殊的形式,Clojures 绕过 JVM 的方式不容易获得 TCO。

因此,您不能apply在此处使用(这将是使用列表中的参数调用函数的解决方案)。

所以你必须坚持结果,foo然后recur与那些。注意旁边:if只有一个分支是 just when

(defn foo [x y] 
  [(dec x) y])

(loop [x 3 y 4]
  (when (> x 0)
    (prn x y)
    (let [[x' y'] (foo x y)] 
      (recur x' y'))))
Run Code Online (Sandbox Code Playgroud)

如果你的领域真的是[x y](例如坐标),我的建议是围绕它构建你的函数,不要在有时使用向量和有时传递 x/y 之间跳转。