用变量参数定义我自己的max函数

eli*_*ocs 5 clojure variadic-functions

我正在学习Clojure解决4clojure上列出的问题.其中一个练习是max使用变量参数创建自己的函数.

我正在尝试使用REPL解决这个简单的问题,我得到了这个解决方案:

(defn my-max 
    [first & more] (calc-max first more))

(defn calc-max 
    [m x] 
        (cond (empty? x) m
            (> (first x) m) (calc-max (first x) (rest x))
            :else calc-max m (rest x)))
Run Code Online (Sandbox Code Playgroud)

哪个工作正常,但练习不允许使用,def因此我必须将两个功能合二为一.当我calc-max用它的代码替换引用时,结果是:

(defn my-max 
    [first & more] 
    ((fn calc-max 
        [m x] 
            (cond (empty? x) m
                (> (first x) m) (calc-max (first x) (rest x))
                :else calc-max m (rest x)))
                    first more))
Run Code Online (Sandbox Code Playgroud)

但是这段代码不起作用并返回下一个错误:

user=> (my-max 12 3 4 5 612 3)
java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)
Run Code Online (Sandbox Code Playgroud)

我想这个错误来自于试图评估calc-max函数的结果,我想这是我的语法错误,但我无法弄清楚如何解决它.

Jus*_*mas 14

这是我用来解决它的功能.关键是不要使用max.

(fn [& args] (reduce (fn [x y] (if (> x y) x y) ) args ) )
Run Code Online (Sandbox Code Playgroud)


Ale*_*Ott 8

真正的错误是你调用参数first- 它将实际first函数重新绑定到数字!只需将名称更改为其他名称,您的变体即可.虽然它可能更好地明确命名函数,而不是调用匿名函数,例如,您可以calc-max使用letfn例如声明为本地函数.所以你的my-max看起来像:

(defn my-max [ff & more]
  (letfn [(calc-max [m x] 
            (cond (empty? x) m
                  (> (first x) m) (calc-max (first x) 
                                            (rest x))
                  :else (calc-max m (rest x))))]
    (calc-max ff more)))
Run Code Online (Sandbox Code Playgroud)

虽然,我认为,您可以编写更简单的代码:

(defn my-max [& more] (reduce max more))
Run Code Online (Sandbox Code Playgroud)