我正在尝试在clojure
中编写递归函数。该函数返回最大数量的给定集合。如果集合是emty,那么它应该返回nil
。
我的代码是:
(defn gum [coll]
(if (empty? coll)
0
(max (first coll)
(gum (rest coll)))))
预期结果:
(gum [1 2 98 -3]) => 98
(gum [1 9]) => 9
(gum []) => nil
但我得到了:
(gum [1 2 98 -3]) => 98
(gum [1 9]) => 9
(gum []) => 0 (not desired result - should be `nil`)
这是因为我将(empty? coll)
的值保持为0
。如果我将其保留为nil
,则(gum [1 2 98 -3])
将无效。有关如何将(gum [])
的{{1}}和nil
的价值同时作为(gum [1 2 98 -3])
的任何建议?
答案 0 :(得分:2)
我想你想要这样的东西:
(defn gum [[head & tail]]
(if (empty? tail)
head
(max head (gum tail))))
我在这里使用的是解构而不是first
和rest
,但它与以下内容相同:
(defn gum [coll]
(let [head (first coll)
tail (rest coll)]
(if (empty? tail)
head
(max head (gum tail)))))
但你应该尽量避免像(max head (gum tail))
这样的结构,因为Clojure无法优化它。尽可能尝试使用recur尾递归:
(defn gum [[head & tail]]
(if (empty? tail)
head
(recur (cons (max head (first tail))
(rest tail)))))
recur
允许Clojure使用Tail Call Optimization将递归调用转换为迭代调用,允许它在常量堆栈空间中运行。它不仅可以使您的代码更快,还可以防止堆栈溢出。
您还应该考虑使用高阶函数而不是递归(如SaltyEgg suggested):
(defn gum [coll]
(if-let [s (seq coll)]
(reduce max s)))
在大多数情况下,它们提供了更简单的解决方案并且它们非常优化。
答案 1 :(得分:1)
试试这个:
(defn gum [coll]
(if (empty? coll)
nil
(reduce max coll)))
答案 2 :(得分:0)
您似乎正在尝试重新定义max
功能?
现在,如果您想了解max函数的工作原理,那么在repl中查看源(source max)
通常是一个好主意:
(defn max
"Returns the greatest of the nums."
{:added "1.0"
:inline-arities >1?
:inline (nary-inline 'max)}
([x] x)
([x y] (. clojure.lang.Numbers (max x y)))
([x y & more]
(reduce1 max (max x y) more)))
请注意,(apply max [])
会抛出异常,而不是返回nil
:ArityException Wrong number of args (0) passed to: core/max clojure.lang.AFn.throwArity (AFn.java:429)
编辑:
这就是为什么首先检查我们是否要应用max
然后(可能)应用的方法,如其他答案所示:
(defn gum [coll]
(if-let [s (seq coll)]
(reduce max s)))
答案 3 :(得分:0)
你不应该在里面调用相同的函数,因为Clojure没有尾递归优化(TRO)。使用(recur arg1 arg2 etc)
迭代下一步。并且不要忘记添加if
语句来离开递归。
答案 4 :(得分:0)
使用与您描述的逻辑相同的方法,可以返回单例元素而不是零:
(defn gum [coll]
(if (or (empty? coll)
(singleton? coll))
(first coll)
(max (first coll) (gum (rest coll)))))
具有:
(defn singleton? [coll]
(if (first coll) (empty? (rest coll)) false))