我正试图在4clojure.com解决计数序列练习.练习是在不使用该count功能的情况下计算集合中元素的数量.
我以为我可以通过递归,通过使用来做到这一点rest.如果我得到的不是空的,我会回来1 + recur on the sequence rest returned.问题是,我最终得到了
java.security.PrivilegedActionException: java.lang.UnsupportedOperationException:
Can only recur from tail position
Run Code Online (Sandbox Code Playgroud)
即使我称之为recur最后一个声明.
(fn [coll] (let [tail (rest coll)]
(if (empty tail)
1
(+ 1 (recur tail)))))
Run Code Online (Sandbox Code Playgroud)
我错过了什么吗?
最后一个声明是添加,而不是调用recur,这就是为什么它不起作用.它在if里面的事实与它无关.(fn [coll] (let [tail (rest coll)] (+ 1 (recur tail))))也行不通.
将这样的函数转换为尾递归的常用方法是使函数接受第二个参数,该参数保存累加器以获得您正在累加的值,然后像这样递归:(recur tail (+ acc 1))而不是尝试将1添加到的结果recur.
作为一般规则:如果你正在对结果做任何事情recur(例如向它添加1),它就不能处于尾部位置,因此它不起作用.
你得到的错误是指出你的最终表达式(+ 1 (recur tail))不是尾部调用优化可优化的(是一个单词?).问题是它需要(+ 1 ...)在堆栈上保留一堆表达式以便评估函数的结果.尾调用优化只有在被调用函数的值是唯一需要知道调用函数返回时才需要的情况下才会发生.
你要写的几乎是一个fold.在这种情况下,函数应该传递集合的其余部分以及到目前为止的计数.
(fn [count coll] (let [tail (rest coll)]
(if (empty tail)
count
(recur (+ 1 count) tail)))))
Run Code Online (Sandbox Code Playgroud)