Clojure - recur 适用于循环或 let 语句?

Clojure - recur applies to loop or let statement?

我在 Clojure 中有一个关于 recur 的问题。如果我在循环内有一个 let 语句,是否可以将 recur 调用应用于 let 语句而不是循环的值? 例如,在这种情况下:

(defn someFunction [listA listB]
  ("do something here...." 
      [new-listA new-listB]))

(defn anotherFunction [listA listB]
  ("do something here...." 
      [new-listA new-listB]))

(defn myFunction [firstList secondList]
  (loop [list1 (someMutation firstList)
         list2 (someMutation secondList)]
    (if (= "true" (someCondition))
      (let [[newlist1 newlist2]
           (someFunction list1 list2)] 
        (recur newlist1 newlist2))
      (anotherFunction list1 list2) )))

(recur newlist1 newlist2) 是应用于循环还是应用于 let? 并且有没有一种方法可以跳过这个 let 语句并直接使用 "someFunction" 返回的两个值调用 recur,假设我不能改变 "someFunction" returns 一个具有两个向量的事实参数?

let 不是有效的重复目标。

您可以在 let 中进行设置以解构向量,因此也可以跳过 let。

此外,引用 true 有点奇怪。这在你的控制之下吗?如果是这样,应该只寻找布尔值 true 然后就可以说 (if (somecondition)...

recur 总是递归到最接近的 loop 或函数,以更接近 recur 形式的为准。它通过编译为一个 loop/jump 语句来实现这一点,该语句更改循环变量的值,然后跳回到 loop/fn 点。这样它只使用一个堆栈帧并且可以 运行 全速。这个设计有些刻意 trade-offs:

  • 你不能交错嵌套循环
  • recur 只能是表达式中的最后一个东西。
  • 重复出现的参数数量必须与 loop/the-function
  • 相同

最后一个要求您保留 let 表达式或类似的等价物,例如解构形式。循环确实允许像函数一样解构参数:

 (loop [[a b] [1 2]]
    (println a b)
    (if (< a 10)
      (recur [(inc a) (inc b)])))
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11

因此您可以编写循环表达式来直接获取 someFunction 的结果

(loop [[list1 list2] [(someMutation firstList) (someMutation secondList)]]
  ...
  (recur (someFunction ...))