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

Posted

技术标签:

【中文标题】Clojure - recur 适用于循环或 let 语句?【英文标题】:Clojure - recur applies to loop or let statement? 【发布时间】:2017-06-04 14:14:50 【问题描述】:

我在 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”返回一个带有两个参数的向量的事实?

【问题讨论】:

【参考方案1】:

recur 总是递归到最接近的loop 或函数,以更接近recur 的形式为准。它通过编译本质上是一个循环/跳转语句来完成此操作,该语句更改循环变量的值,然后跳回到循环/fn 点。这样它只使用一个堆栈帧并且可以全速运行。这种设计有一些有意的取舍:

不能交错嵌套循环 recur 只能是表达式中的最后一项。 必须有与循环/函数相同数量的参数才能重复

最后一个要求您保留 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 ...))

【讨论】:

【参考方案2】:

let 不是有效的重复目标。

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

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

【讨论】:

以上是关于Clojure - recur 适用于循环或 let 语句?的主要内容,如果未能解决你的问题,请参考以下文章

如何在clojure中的每一行打印数字列表?

Clojure布尔值true或false

my clojure note

如何从clojure中的给定两个值逐个调用函数

函数式编程公理

如何使clojure程序结构更容易识别?