1
\$\begingroup\$

I've started learning Clojure a few days ago and I wrote this code that factorises numbers. How do I make it better? Is there any way to avoid doing it with a loop? Is that how I am supposed to code in Clojure?

(defn classify [n]
  (loop [n n
         i 2
         f []]
    (cond
      (= n i) (conj f i)
      (= (mod n i) 0) (recur (/ n i) 2 (conj f i))
      :else (recur n (inc i) f))))
\$\endgroup\$
1
  • 1
    \$\begingroup\$ This is functional. loop is the functional way to "loop" in Clojure. doseq for example would be the "bad", imperative way of doing things. \$\endgroup\$ May 2, 2021 at 17:35

1 Answer 1

2
\$\begingroup\$

Maybe a slightly more functional way to express your algorithm is ...

(defn classify [n]
  (letfn [(factors-from [i from]
            (cond
              (= i 1) '()
              (zero? (mod i from)) (cons from (factors-from (quot i from) from))
              :else (recur i (inc from))))]
   (factors-from n 2)))
  • The local function factors-from plays the role of the loop.
  • The recursive call when we have found a factor saves us carrying the sequence of factors as a parameter.
  • We use quot instead of / for the division, since it is simpler.
  • The terminal case is 1instead of from. This gives the correct answer of an empty factor list when n is 1.
  • The normal case, when we don't find a factor, is a straight tail recursion, hence can be a recur.

There is no danger of running out of stack space, since the smallest number that could do so is about 2^10000, far beyond anything long arithmetic could deal with.

\$\endgroup\$
1
  • \$\begingroup\$ Thank you! I can learn a lot by reading this code and trying out the functions you used. \$\endgroup\$ May 4, 2021 at 9:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.