(ns example
  (:gen-class))


(defn primes-hashmap
  "Infinite sequence of primes using an incremental Sieve or Eratosthenes with a Hashmap"
  []
  (letfn [(nxtoddprm [c q bsprms cmpsts]
            (if (>= c q) 
              
              (let [p2 (* (first bsprms) 2),
                    nbps (next bsprms),
                    nbp (first nbps)]
                (recur (+ c 2) (* nbp nbp) nbps (assoc cmpsts (+ q p2) p2)))

              (if (contains? cmpsts c)
                
                (recur (+ c 2) q bsprms
                       (let [adv (cmpsts c), ncmps (dissoc cmpsts c)]
                         (assoc ncmps
                           (loop [try (+ c adv)] 
                             (if (contains? ncmps try)
                               (recur (+ try adv))
                               try))
                           adv)))
                
                (cons c (lazy-seq (nxtoddprm (+ c 2) q bsprms cmpsts))))))]
    (do (def baseoddprms (cons 3 (lazy-seq (nxtoddprm 5 9 baseoddprms {}))))
        (cons 2 (lazy-seq (nxtoddprm 3 9 baseoddprms {}))))))


(defn primorial [n]
  " Function produces the nth primorial number"
  (if (= n 0)
    1                                                           
    (reduce *' (take n (primes-hashmap)))))                     


(let [start (System/nanoTime)
      elapsed-secs (fn [] (/ (- (System/nanoTime) start) 1e9))]   
  (doseq [i (concat (range 10) [1e2 1e3 1e4 1e5 1e6])
          :let [p (primorial i)]]                               
    (if (< i 10)
      (println (format "primorial (%7d ) =%10d" i (biginteger p)))         
      (println (format "primorial (%7d ) has%8d digits\tafter%.3f secs"   
                       (long i) (count (str p)) (elapsed-secs))))))