My beginnings @Clojure - Own Codes dont work, dont

Viewed 119

I'm a programming beginner, switching from Python to Clojure now. I am working on a prime number code, but I don't get the mistake. I want to practice recursion also

(defn true-division [n i]
  (= (/ n i) (quot n i)))
;proves if division is possible

(defn is-prime-number2 [n]
  (def i (atom (- n 1)))
  (while (> @i 1)
    (do
      (conj list (true-division n @i))
      (swap! @i dec))))

;should fill an empty list with true and false statements
    ;in the final function I want to check if there is a true in the list 

(println (is-prime-number2 12))

2nd Code as a recursive try:

(defn true-division [n i]
  (= (/ n i) (quot n i))
  )

(println (true-division 4 5))


(defn is-prime-number [n]
  (let [list []]
    (loop [i (- n 1)]
      (while(> i 0)
        (do
          (conj list (true-division n i))
          (recur (dec i)))))))

(println (is-prime-number 12))

My preferred way would be to stay in a loop/iteration - if there comes a true, then interrupt the loop. I don't know how to code this with the basics I learned so far. If I'm creating loops, I always struggle with breaking them when the condition is reached.

In this example I would create a final function with an if to prove if there is a true in the list and print out the result.

I heard about the lazy function but I want to practice the syntax and functions, so I would appreciate your help on the way I planned :)

2 Answers

The algorithm you are suggesting of testing if a number can be divided by any number less than that number can be implemented using a loop or using a sequence. I believe we need to pay special attention to the fact that 1 is usually not considered a prime number. This is what a loop-based implementation could look like:

(defn true-division? [n i]
  (zero? (rem n i)))

(defn is-prime-number-using-loop? [n]
  (and (<= n 2)
       (loop [i (dec n)]
         (cond
           (= i 1) true
           (true-division? n i) false
           :else (recur (dec i))))))

(filter is-prime-number-using-loop? (range 50))
;; => (2 3 5 7 11 13 17 19 23 29 31 37 41 43 47)

This is what a sequence-based implementation could look like:

(defn is-prime-number-using-seq? [n]
  (and (<= 2 n)
       (not-any? (partial true-division? n) (range 2 n))))

(filter is-prime-number-using-seq? (range 50))
;; => (2 3 5 7 11 13 17 19 23 29 31 37 41 43 47)

The sequence-based implementation is arguably more concise whereas the loop-based one is likely to give somewhat better performance on the JVM using a recent Clojure implementation, although I did not measure that.

Then there are optimizations you can do. For example, it would be enough to test divisibility only up to the square root of the number. And if there are many numbers in a range that you want to test, Sieve of Eratosthenes would probably be a good approach.

;; source http://www.sicpdistilled.com/section/1.2.6/
;; sicpdistilled is SICP in Clojure

(defn smallest-divisor [n]
  (find-divisor n 2))

(defn find-divisor [n test-divisor]
  (cond (> (square test-divisor) n) n
        (divides/ test-divisor n) test-divisor
        :else (find-divisor n (+ test-divisor 1))))

(defn divides? [a b]
  (= (remainder b a) 0))

(defn prime? [n]
  (= n (smallest-divisor n)))

I highly recommend you to read a short form of SICP in Clojure http://www.sicpdistilled.com/section/1.2.6/ .

Related