Во-первых, вы не можете просто поместить круглые скобки в коде, как на других языках. Они означают что-то конкретное в Clojure (и других шутках) при оценке кода, а именно первое, что в списке есть глагол; функция для вызова. Вложенные скобки означают повторные обращения к результату функции. Поэтому, если у вас есть функция alice
, которая возвращает функцию, например, так (оставайтесь со мной, я пытаюсь объяснить ошибку, которую вы получаете;)):
(defn alice []
(fn [] :bob))
тогда вы можете назвать это так
(alice) ;; => #function[user/alice/fn--6930]
и он вернет функцию, которую вы создали внутри, и вы можете вызвать эту анонимную функцию следующим образом:
((alice)) ;; => :bob
чтобы получить результат этой функции. Извините, если это немного необычно, но у паренов есть смысл, и это причина ошибки, которую вы получаете:
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn
Это означает, что вы пытаетесь вызвать номер как функцию. clojure.lang.IFn
- это способ Clojure сказать «то, что я ожидал, было чем-то, что я мог бы назвать функцией». К java.lang.Long
означает среднее число Clojure. ClassCastException означает, что я видел одно, а ожидал другого. На самом деле, эта ошибка пытается сказать, что вы написали открытый код (
и добавили что-то с именем числа, а не функции. Это похоже на то, что вы написали divide(n (get-divisors n))
вместо (divide n (get-divisors n))
, потому что при оценке divide(n (get-divisors n))
он сначала пытается оценить divide
и обнаруживает, что это функция, но не пытается ее вызвать. Затем он смотрит на следующую форму (n (get-divisors n))
и пытается спросить, что такое n
, и находит его число, которое нельзя вызвать как функцию. Имеет смысл?
В вашем псевдокоде у вас есть массив, к которому вы добавляете данные для сбора результатов, в то же время повторяя цикл для построения результатов. Это очень обязательный способ решения проблемы, а не то, как Clojure пытается побудить вас решать проблемы. Clojure стремится учиться более ориентированному на данные способу решения проблемы. Один из способов думать о проблеме - это то, как она сформулирована на английском языке. Получив число n
, возьмите все числа, меньшие его квадратного корня, и проверьте, делятся ли они на n
. Если этот список пуст, верните true, иначе верните false. В Clojure вы могли бы написать:
(defn divide? [a b]
(zero? (mod a b)))
(defn no-divisors? [n]
(->> (range 2 n)
(take-while #(< (* % %) n))
(filter (partial divide? n))
empty?))
Здесь мы используем макрос ->>
, чтобы взять ленивую последовательность чисел от 2 до n
, затем ограничиваем эту последовательность, используя take-while
, только теми, у которых квадрат числа меньше n
, Затем мы проверяем, что каждый делится на n, используя функцию divide?
, и, наконец, спрашиваем, является ли список empty?
. Поскольку последовательности Clojure являются ленивыми, никаких реальных вычислений не происходит, пока мы не попытаемся оценить результат, используя empty?
, который остановится, когда он достигнет элемента в последовательности. Это делает его более эффективным, чем обход всего списка для больших значений n
.
Надеюсь, это поможет.
P.S. Я не уверен, что ваша реализация get-divisors
совершенно правильная.