0

我正在尝试在clojure. 该函数返回给定集合的最大数量。如果集合是空的,那么它应该返回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)as的值0。如果我保留它,nil那么(gum [1 2 98 -3])将无法正常工作。关于如何同时带来(gum [])asnil(gum [1 2 98 -3])as的价值的任何建议98

4

5 回答 5

3

我想你想要这样的东西:

(defn gum [[head & tail]]
  (if (empty? tail)
      head
      (max head (gum tail))))

我在这里使用解构而不是firstand 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 使用尾调用优化将您的递归调用转换为迭代调用,允许它在恒定的堆栈空间中运行。它不仅使您的代码更快,而且还保护它免受堆栈溢出。

您还应该考虑使用高阶函数而不是递归(如SaltyEgg 建议的那样):

(defn gum [coll]
  (if-let [s (seq coll)]
    (reduce max s)))

在大多数情况下,它们提供了更简单的解决方案。而且它们经过了很好的优化。

于 2013-10-24T10:03:31.370 回答
1

尝试这个:

(defn gum [coll]
 (if (empty? coll)
  nil 
  (reduce max coll)))
于 2013-10-24T09:50:37.443 回答
0

看起来您正在尝试重新定义max功能?

现在,如果您想了解 max 函数的工作原理,通常最好查看(source max)repl 中的源代码:

(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 [])将引发异常而不是返回nilArityException 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)))
于 2014-11-30T16:04:26.747 回答
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))
于 2019-12-17T09:55:28.003 回答
0

您不应该在内部调用相同的函数,因为 Clojure 没有尾递归优化 (TRO)。用于(recur arg1 arg2 etc)迭代下一步。并且不要忘记添加if声明以离开递归。

于 2017-03-18T13:18:44.680 回答