2

我是 Clojure 的新手,为了练习,我正在尝试对半随机数应用一个简单的算法。

几天前,我在 clojure 的文档中读到了循环,以及它们是如何使用recur的,所以我尝试用这行代码编写一个循环:

(def numbers_semi_random
  (fn []      
    (loop[Xn 4 count 0]                    
     (while (and (not (= Xn m)) (< count m))
       (println (mod (+ (* 5.0 Xn) 7.0) m))
       (recur (mod (+ (* 5.0 Xn) 7.0) m) (inc count))    
))))

但是当我执行代码时,会显示此错误

CompilerException java.lang.UnsupportedOperationException: Can only recur from tail position, compiling

发生了什么?recur是不是在函数的尾部?

4

2 回答 2

7

您的意图似乎很可能通过使用when代替来实现while(您的循环将继续打印更新的值,Xn直到满足条件),但要解释异常:

从编译器的角度来看,问题在于虽然while表单确实相对于您的 位于尾部位置loop,但while宏的扩展使得while' 主体中的任何内容都没有相对于while表单处于尾部位置。(如果身体在while表格的尾部位置,它也将在封闭的尾部位置loop。)

之所以如此,是因为它while会扩展为表达式并在用户提供的主体之后loop提供自己的表达式:recur

(while test
  body...)

;; expands to

(loop []
  (when test
    body...
    (recur)))

所以,如果你提供 arecur作为身体的一部分while,你得到的是

(loop []
  (when test
    ...
    (recur ...) ; from user code
    (recur)))

在这里,用户提供(recur ...)的相对于它的立即封闭不在尾部位置loop,这就是编译器所抱怨的。

于 2015-02-14T05:09:37.407 回答
3

尾部位置是在离开范围之前需要评估的最后一个形式。使用 时loop,该recur语句必须能够以新的绑定重新开始,不再需要完成前一个循环的进一步计算。

在您的代码中,您whileloop. 您尝试调用recur的位置不在循环的尾部位置(尽管它在其尾部的尾部)。

也许您打算recurwhile? 但是循环绑定Xn和测试中count的全局变量的比较让我觉得这里还有更多需要解开的东西。你想要多少个嵌套循环?mwhile

于 2015-02-14T03:42:19.857 回答