Определение моей собственной функции max с переменными аргументами - PullRequest
5 голосов
/ 21 сентября 2011

Я изучаю 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)))

Что отлично работает, но упражнение не позволяет использовать 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))

Но этот код не работает и возвращает следующую ошибку:

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)

Я предполагаю эту ошибкуисходит из попытки оценить результат функции calc-max, и я предполагаю, что это синтаксическая ошибка с моей стороны, но я не могу понять, как ее решить.

Ответы [ 5 ]

14 голосов
/ 05 апреля 2012

Вот функция, которую я использовал для ее решения.Дело не в том, чтобы использовать max вообще.

(fn [& args] (reduce (fn [x y] (if (> x y) x y) ) args ) )
8 голосов
/ 21 сентября 2011

Настоящая ошибка в том, что вы вызвали параметр 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)))

Хотя я думаю, что вы можете написать более простой код:

(defn my-max [& more] (reduce max more))
4 голосов
/ 21 сентября 2011

Ваша функция не работает, потому что first in fn обрабатывается как функция, а не как входное значение.Поэтому, когда вы пишете

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

, это означает, что 12 не может привести к функционированию.Просто его можно переписать как

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

или даже без fn

(defn my-max [x & xs]
  (cond (empty? xs) x
        (> (first xs) x) (recur (first xs) (rest xs))
        :else (recur x (rest xs))))
0 голосов
/ 07 мая 2019

Не так хорошо, как уменьшить, но хорошо ба:

(fn [& args] (цикл [l args, maxno (первые аргументы)] (если (пусто? л) MAXNO (if (> maxno (first l)) (рецидив (отдых) максно) (recur (rest l) (first l))))))

Можно использовать cond, я полагаю

0 голосов
/ 21 сентября 2011

Чтобы немного подробнее рассказать об исключении, которое вы видите: всякий раз, когда Clojure бросает в вас что-то вроде

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

, это означает, что он пытался вызвать функцию, но вещь, которую он пытался вызвать, не былафункция, но что-то еще.Это обычно происходит, когда у вас есть такой код

(smbl 1 2 3)

Если smbl относится к функции, clojure выполнит ее с параметрами 1, 2 и 3. Но если smbl не относится к функциитогда вы увидите ошибку, подобную приведенной выше.Это был мой указатель при просмотре вашего кода, и, как указал 4e6, (first x) является виновником, потому что вы назвали аргумент своей функции first.

...