3

What would be a more correct functional way to write the following code which checks if a number is prime or not:

(defn prime? [n]
  (loop [k 2]
    (cond
     (< k n) (if (not= 0 (mod n k))
               (recur (inc k))
               (println n "is not prim"))
     :else (println n "is prim"))))
Thumbnail
  • 13,293
  • 2
  • 29
  • 37

2 Answers2

8

Regardless of which algorithm you use to test primality, the "correct functional way" would be for your prime? function to return true or false. As it stands, your function returns nil and has side effects (prints something out).

You could then do (println (prime? x)) to check a particular number, and have the side effects constrained to that single statement.

Diego Basch
  • 12,764
  • 2
  • 29
  • 24
  • thanks for the explanation. What i still cant understand is that a `print` function is known to have side effects, but if we provide `print` with the same argument it will give always the same output. So why is `print` a side-effected function? –  Aug 09 '15 at 20:17
  • 2
    @teymuri "Output" in purely functional programming typically refers to return values. While `print` always returns `nil`, it has a side-effect (i.e. it observably does something other than computing things and returning a result) of writing to `*out*`. –  Aug 09 '15 at 21:11
7

A simpler way using standard library functions such as every? and range:

(defn divisible? [a b]
  (zero? (mod a b)))

(defn prime? [n]
  (and (> n 1) (not-any? (partial divisible? n) (range 2 n))))

and refactoring I/O into a separate function for greater reuse:

(defn format-primality [n]
  (str n " " (if (prime? n) "is prim" "is not prim")))

(def print-primality
  (comp println format-primality))

Example:

user=> (map (fn [n] [n (prime? n)]) (range 1 15))
([1 false] [2 true] [3 true] [4 false] [5 true] [6 false] [7 true]
 [8 false] [9 false] [10 false] [11 true] [12 false] [13 true] [14 false])
  • very nice example! So would also this version (is just an alteration of yours) be a pure functional one without side effects? `(defn prime? [n] (if (some #(= 0 (mod n %)) (range 2 n)) "Not prim" "Prim"))` –  Aug 09 '15 at 19:37
  • @teymuri That function always gives the same result for the same arguments, and it does not ever perform any side-effects; so yes, it is pure. FYI, in my example all functions except `print-primality` are pure. –  Aug 09 '15 at 20:02
  • @elyse You don't need to check till `n`. `sqrt n` is the max limit to check if the number is prime which saves a lot of time. http://stackoverflow.com/q/5811151/2610955 – xtreak Aug 10 '15 at 07:37