One thing I learned during the course of completing problem 37 is that I have been using the wrong definition of prime?
in previous problems. Technically, the number 1 is not in fact prime, yet the old definition of prime?
would treat it as if it were.
The first bit of (working) code that I wrote looked like this and reused old code for prime?
and as-digits
.
(defn as-int [coll]
(Integer/parseInt (apply str coll)))
(defn r-truncatable-prime? [n]
(cond
(= n 1) false
(< n 10) (prime? n)
(prime? n) (recur (as-int (butlast (as-digits n))))
true false))
(defn l-truncatable-prime? [n]
(cond
(= n 1) false
(< n 10) (prime? n)
(prime? n) (recur (as-int (rest (as-digits n))))
true false))
(defn lr-truncatable-prime? [n]
(and (l-truncatable-prime? n)
(r-truncatable-prime? n)))
(defn euler-37 []
(reduce + (take 11 (filter lr-truncatable-prime? (iterate inc 10)))))
Repetition in code really bugs me because it’s easy to introduce bugs if I accidentally update one function but not it’s companion, so let’s improve the above definition a little and make it self-contained:
(use '[clojure.contrib.lazy-seqs :only (primes)])
(defn prime? [n]
(if (> 2 n)
false
(not-any? #(zero? (rem n %)) (take-while #(<= (* % %) n) primes))))
(defn as-digits [num]
(map #(Character/getNumericValue %) (str num)))
(defn as-int [coll]
(Integer/parseInt (apply str coll)))
(defn lr-truncatable-prime? [n]
(let [trunc-prime? (fn [f n]
(cond
(< n 10) (prime? n)
(prime? n) (recur f (as-int (f (as-digits n))))
true false))]
(and (trunc-prime? butlast n)
(trunc-prime? rest n))))
(defn euler-37 []
(reduce + (take 11 (filter lr-truncatable-prime? (iterate inc 10)))))
I think that is remarkably readable. See you tomorrow!