我可以设置一个默认参数并对其进行常规递归,但出于某些原因我无法使用recur
进行尾部优化...我一直收到java.lang.UnsupportedOperationException: nth not supported on this type: Long
错误。< / p>
例如,对于Tail Call Factorial,这里有效,但是没有针对尾调用递归进行优化,并且对于大型递归栈也会失败。
(defn foo [n & [optional]]
(if (= n 0) (or optional 1)
(foo (dec n) (*' (or optional 1) n))))
我在(foo 3)
当我尝试获得TCO时,我得到了不支持的操作错误......
(defn foo [n & [optional]]
(if (= n 0) (or optional 1)
(recur (dec n) (*' (or optional 1) n))))
我以同样的方式称呼(foo 3)
为什么这种差异会导致错误?我究竟能用可选的默认参数进行TCO吗?
谢谢!
编辑:
当我尝试在递归调用中取出(or optional 1)
并将其设为optional
时,我得到一个空异常错误......这是有道理的。
当我尝试在递归调用中从'
删除*'
时,这也无法修复
编辑:我也希望在没有loop
的情况下也这样做
答案 0 :(得分:2)
Recur没有重新进入该功能,它只是回到顶部(vararging不再发生)...复发一个集合,你会没事的。
我个人认为应该在recur
文档字符串中提及,或至少出现在文档中。需要花点时间去理解发生了什么(我必须检查Clojure编译器源以及编译的类。)
答案 1 :(得分:1)
您可以为多个不同的arities提供一个功能。这可能是你之后的事情?
(defn foo
([n]
(foo n 1))
([n optional]
(if (= n 0)
(or optional 1)
(recur (dec n) (*' (or optional 1) n)))))
我不太明白为什么会出现错误,但是通常不会在带有可选参数的函数中使用recur。
修改:在阅读其他答案链接后,我现在了解problem。 recur并没有像你调用函数那样去构造其余的args。如果你将一个集合作为第二个arg重复出现,它会起作用,但是对于两个不同的arities来说,显然可能更好:
(defn foo [n & [optional]]
(if (= n 0)
(or optional 1)
(recur (dec n) [(*' (or optional 1) n)])))
答案 2 :(得分:1)
为什么这种差异会导致错误?
foo
来电
n
)之后的所有内容放入幕后的seq中,这可以被解构recur
致电foo
n
我究竟能用可选的默认参数进行TCO吗?
recur
,如下所示:(defn foo [n & [optional]]
(if (= n 0) (or optional 1)
(recur (dec n) [(*' (or optional 1) n)])))
(foo 3)
;;=> 6