https://github.com/clojure/clojure/blob/f572a60262852af68cdb561784a517143a5847cf/src/clj/clojure/core/specs.clj




(let [ignore? (fn-or fn? t/protocol? t/multimethod? t/unbound? t/namespace? t/thread?)]
  (->> (all-ns)
       (map+    ns-interns)
       (join    {})
       (map+    val)
       (remove+ #{#'clojure.core/*1
                  #'clojure.core/*2
                  #'clojure.core/*3
                  #'clojure.core/*data-readers*
                  #'clojure.core/default-data-readers
                  #'clojure.tools.reader/default-data-readers
                  #'clojure.core.async.impl.timers/timeouts-queue
                  #'clojure.tools.analyzer.jvm/default-passes
                  #'aleph.http/default-connection-pool
                  #'aleph.http/default-response-executor
                  #'clojure.core.async.impl.ioc-macros/passes
                  #'byte-streams/inverse-conversions
                  #'byte-streams/conversions})
       (remove+ (rcomp deref (fn-or ignore? (fn-and var? (fn-> deref ignore?)))))
       (map+    (juxt identity (fn-> deref quantum.core.meta.bench/shallow-byte-size)))
       (join    {})
       (map+    val)
       (reduce  +)
       (#(quantum.measure.convert/convert % :bytes :MB))
       double))

(def-map 1)

; -> 18.21 MB... there must be lots of data not referenced by vars

; TODO log these stats when every namespace is compiled
(->> (java.lang.management.ManagementFactory/getMemoryPoolMXBeans)
     (mapv (juxt #(.getName %) #(.getType %) #(.getUsage %))))

 {:code-cache 25.52099609375,
 :metaspace 203.1375122070312, (some of this is definitely garbage collected)
 :compressed-class-space 69.5936279296875}


TODO make sure to set a global onerror handler for PhantomJS (via a flag of course)

TODO decrease memory footprint? (it's huge!)
TODO allow return types for `defnt` like `sequential?`
TODO also allow return types like :whatever/validator

TODO longs vs. long-array

; TODO fn (params-match? ->double 1) -> true; (params-match? ->double "asd") -> false
; TODO do fast-as-possible ops given math expr
; (* a (- b c) v) -> (scale (* a (- b c)) v)

; TODO:

(fnt [^indexed? x a]
  (conj' x a)) ; and have it know what function needs to be looked up

(:abcde my-validated-map) ; and know what its type will be




(defn dropr-digit
  ([n] (quot n 10))
  ([digits n]
    (if (<= digits 0)
        n
        (recur (dec digits) (dropr-digit n)))))

(defn count-digits-integral
  "Counts the digits of a number `n` not having a decimal portion."
  ([n] (count-digits-integral (dropr-digit n) 1))
  ([n d] (if (zero? n)
             d
             (recur (dropr-digit n) (inc d)))))

(defn ->integral [n] (- n (->decimal n)))

(defn ->decimal [n] (rem n 1))

(defn pow-10 [n] (long (Math/pow 10 (int n))))

(defn decimal->integer-like-decimal
  "E.g. 0.003812317M -> 1003812317N
   `n` must be 0 ≤ n < 1
   Returns a `bigint`."
  [n]
  (if (zero? n)
      0
      (bigint (str "1" (subs (str (.stripTrailingZeros (bigdec n))) 2)))))

(defn integer-like-decimal->decimal
  "E.g. 1003812317N -> 0.003812317M
   `n` must be an integer.
   Returns a `bigdec`."
  [n]
  (bigdec (str "0." (subs (str n) 1))))

(->decimal 1/4)


(defn num-decimal-places [n]
  (-> n ->decimal bigdec (.stripTrailingZeros) (.scale) (max 0)))

(defn truncate-digits
  "Truncates an integer `n` the specified number of `digits`, replacing
   the truncated portion with 0s."
  [digits n]
  (if (<= digits 0)
      n
      (* (dropr-digit digits n)
         (pow-10 digits))))

(defn exact [n]
  (if (or (double?  n)
          (float?   n)
          (decimal? n))
      (rationalize n)
      n))
