当我需要给递归函数一个可选参数时,我正在为这个挑战写一个答案.我最终得到的东西相当于:
(defn func [a & [b?]]
(if b?
b?
(recur a a)))
Run Code Online (Sandbox Code Playgroud)
我的意图是b?作为一个可选参数.如果没有提供,它将nil通过解构默认为默认.
它没有运行,而是给了我一个错误:
(func 1)
UnsupportedOperationException nth not supported on this type: Long clojure.lang.RT.nthFrom (RT.java:947)
Run Code Online (Sandbox Code Playgroud)
经过一些调试后,我意识到由于某种原因,rest参数不是我所期望的列表,而只是传递的数字!错误即将发生,因为它试图破坏数字.
我可以通过删除参数列表中的包装器列表来修复它:
(defn func [a & b]
...
Run Code Online (Sandbox Code Playgroud)
但这看起来不错.我知道rest参数应该是一个列表,但b实际上只是一个数字.如果我使用"未优化的"递归,它可以像我期望的那样工作:
(defn func2 [a & [b?]]
(if b?
b?
(func2 a a)))
(func2 1)
=> 1
Run Code Online (Sandbox Code Playgroud)
谁能解释一下这里发生了什么?
Joh*_*ter 10
这似乎是一个已知的差异
; 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.
Run Code Online (Sandbox Code Playgroud)
这是描述差异的最后一条评论.