使用Default Optional参数并在Clojure中重复使用

时间:2016-09-30 02:04:05

标签: recursion clojure tail-call-optimization

我可以设置一个默认参数并对其进行常规递归,但出于某些原因我无法使用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的情况下也这样做

3 个答案:

答案 0 :(得分:2)

a known issue

  

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)

  

为什么这种差异会导致错误?

  • 简而言之,它试图破坏Long,它无法
  • 直接foo来电
    • 采取n个参数
    • 自动将第一个参数(n)之后的所有内容放入幕后的seq中,这可以被解构
  • recur致电foo
    • 正好有2个参数
    • 第一个论点:n
    • 第二个论点:与其余参数一致的东西
  

我究竟能用可选的默认参数进行TCO吗?

  • 只需将第二个参数包装到recur,如下所示:
(defn foo [n & [optional]]
  (if (= n 0) (or optional 1)
  (recur (dec n) [(*' (or optional 1) n)])))

(foo 3)
;;=> 6

推荐

  • 虽然他没有回答你的问题,@ DanielCompton的建议是以更清晰,更有效的方式完全避免问题的方法