开发者

Defining my own max function with variable arguments

开发者 https://www.devze.com 2023-04-06 16:56 出处:网络
I\'m learning Clojure solving the problems listed on 4clojure. One of the exercises is to create your own max function with variable arguments.

I'm learning Clojure solving the problems listed on 4clojure. One of the exercises is to create your own max function with variable arguments.

I'm trying to solve this easy problem using the REPL and I got to this solution:

(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)))

Which works开发者_C百科 fine but the exercise doesn't allow the use of def and therefore I must crunch both functions into one. When I replace the calc-max reference with its code the result is:

(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))

But this code doesn't work and returns the next error:

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)

I guess this error comes from trying to evaluate the result of the calc-max function and I guess it's a syntax error on my part, but I can't figure out how to resolve it.


Here is the function I used to solve it. The point is not to use max at all.

(fn [& args] (reduce (fn [x y] (if (> x y) x y) ) args ) )


Real error is that you called parameter first - it rebinds real first function to number! Just change name to something other, and your variant will work. Although it maybe better explicitly name function, instead of calling anonymous function, for example, you can declare calc-max as local function using letfn, for example. So your my-max will look like:

(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)))

Although, I think, that you can write simpler code:

(defn my-max [& more] (reduce max more))


Your function doesn't work because first in fn treated as function and not as input value. So when you write

user=> (my-max 12 3 4 5 612 3)

it's talling that can't cast 12 to function. Simply, it can be rewrited as

(defn my-max1 [fst & 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))))
    fst more))

or even without fn

(defn my-max [x & xs]
  (cond (empty? xs) x
        (> (first xs) x) (recur (first xs) (rest xs))
        :else (recur x (rest xs))))


To elaborate a little more on the exception that you are seeing: whenever Clojure throws something like

java.lang.Integer cannot be cast to clojure.lang.IFn

at you it means that it tried to call a function but the thing it tried to call was not a function but something else. This usually occurs when you have code like this

(smbl 1 2 3)

If smbl refers to a function, clojure will execute it with parameters 1 2 and 3. But if smbl doesn't refer to a function then you will see an error like the one above. This was my pointer in looking through your code and, as 4e6 pointed out, (first x) is the culprit here because you named your function argument first.


Not as good as the reduce but ok ba:

(fn [& args] (loop [l args, maxno (first args)] (if (empty? l) maxno (if (> maxno (first l) ) (recur (rest l) maxno) (recur (rest l) (first l))))))

Can use cond I suppose

0

精彩评论

暂无评论...
验证码 换一张
取 消