当我需要为递归函数提供一个可选参数时,我正在为this挑战写一个答案。我最终得到的东西相当于:
(defn func [a & [b?]]
(if b?
b?
(recur a a)))
我的意图是b?
充当可选参数。如果没有提供,它将通过解构默认为nil
。
它没有运行,而是给了我一个错误:
(func 1)
UnsupportedOperationException nth not supported on this type: Long clojure.lang.RT.nthFrom (RT.java:947)
经过一些调试后,我意识到由于某种原因,rest参数不是我期望的列表,而只是传递的数字!错误即将发生,因为它试图破坏数字。
我可以通过删除参数列表中的包装列表来修复它:
(defn func [a & b]
...
但这看起来不错。我知道其余参数应该是一个列表,但b
实际上只是一个数字。如果我使用“未优化的”递归,它就像我期望的那样工作:
(defn func2 [a & [b?]]
(if b?
b?
(func2 a a)))
(func2 1)
=> 1
有谁能解释这里发生了什么?
答案 0 :(得分:10)
这似乎是known difference
; Note that recur can be surprising when using variadic functions.
(defn foo [& args]
(let [[x & more] args]
(prn x)
(if more (recur more) nil)))
(defn bar [& args]
(let [[x & more] args]
(prn x)
(if more (bar more) nil)))
; The key thing to note here is that foo and bar are identical, except
; that foo uses recur and bar uses "normal" recursion. And yet...
user=> (foo :a :b :c)
:a
:b
:c
nil
user=> (bar :a :b :c)
:a
(:b :c)
nil
; The difference arises because recur does not gather variadic/rest args
; into a seq.
这是描述差异的最后一条评论。