Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
branch: master
7494 lines (6667 sloc) 249.979 kb
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns ^{:doc "The core Clojure language."
:author "Rich Hickey"}
clojure.core)
(def unquote)
(def unquote-splicing)
(def
^{:arglists '([& items])
:doc "Creates a new list containing the items."
:added "1.0"}
list (. clojure.lang.PersistentList creator))
(def
^{:arglists '([x seq])
:doc "Returns a new seq where x is the first element and seq is
the rest."
:added "1.0"
:static true}
cons (fn* ^:static cons [x seq] (. clojure.lang.RT (cons x seq))))
;during bootstrap we don't have destructuring let, loop or fn, will redefine later
(def
^{:macro true
:added "1.0"}
let (fn* let [&form &env & decl] (cons 'let* decl)))
(def
^{:macro true
:added "1.0"}
loop (fn* loop [&form &env & decl] (cons 'loop* decl)))
(def
^{:macro true
:added "1.0"}
fn (fn* fn [&form &env & decl]
(.withMeta ^clojure.lang.IObj (cons 'fn* decl)
(.meta ^clojure.lang.IMeta &form))))
(def
^{:arglists '([coll])
:doc "Returns the first item in the collection. Calls seq on its
argument. If coll is nil, returns nil."
:added "1.0"
:static true}
first (fn ^:static first [coll] (. clojure.lang.RT (first coll))))
(def
^{:arglists '([coll])
:tag clojure.lang.ISeq
:doc "Returns a seq of the items after the first. Calls seq on its
argument. If there are no more items, returns nil."
:added "1.0"
:static true}
next (fn ^:static next [x] (. clojure.lang.RT (next x))))
(def
^{:arglists '([coll])
:tag clojure.lang.ISeq
:doc "Returns a possibly empty seq of the items after the first. Calls seq on its
argument."
:added "1.0"
:static true}
rest (fn ^:static rest [x] (. clojure.lang.RT (more x))))
(def
^{:arglists '([coll x] [coll x & xs])
:doc "conj[oin]. Returns a new collection with the xs
'added'. (conj nil item) returns (item). The 'addition' may
happen at different 'places' depending on the concrete type."
:added "1.0"
:static true}
conj (fn ^:static conj
([] [])
([coll] coll)
([coll x] (. clojure.lang.RT (conj coll x)))
([coll x & xs]
(if xs
(recur (conj coll x) (first xs) (next xs))
(conj coll x)))))
(def
^{:doc "Same as (first (next x))"
:arglists '([x])
:added "1.0"
:static true}
second (fn ^:static second [x] (first (next x))))
(def
^{:doc "Same as (first (first x))"
:arglists '([x])
:added "1.0"
:static true}
ffirst (fn ^:static ffirst [x] (first (first x))))
(def
^{:doc "Same as (next (first x))"
:arglists '([x])
:added "1.0"
:static true}
nfirst (fn ^:static nfirst [x] (next (first x))))
(def
^{:doc "Same as (first (next x))"
:arglists '([x])
:added "1.0"
:static true}
fnext (fn ^:static fnext [x] (first (next x))))
(def
^{:doc "Same as (next (next x))"
:arglists '([x])
:added "1.0"
:static true}
nnext (fn ^:static nnext [x] (next (next x))))
(def
^{:arglists '(^clojure.lang.ISeq [coll])
:doc "Returns a seq on the collection. If the collection is
empty, returns nil. (seq nil) returns nil. seq also works on
Strings, native Java arrays (of reference types) and any objects
that implement Iterable."
:tag clojure.lang.ISeq
:added "1.0"
:static true}
seq (fn ^:static seq ^clojure.lang.ISeq [coll] (. clojure.lang.RT (seq coll))))
(def
^{:arglists '([^Class c x])
:doc "Evaluates x and tests if it is an instance of the class
c. Returns true or false"
:added "1.0"}
instance? (fn instance? [^Class c x] (. c (isInstance x))))
(def
^{:arglists '([x])
:doc "Return true if x implements ISeq"
:added "1.0"
:static true}
seq? (fn ^:static seq? [x] (instance? clojure.lang.ISeq x)))
(def
^{:arglists '([x])
:doc "Return true if x is a Character"
:added "1.0"
:static true}
char? (fn ^:static char? [x] (instance? Character x)))
(def
^{:arglists '([x])
:doc "Return true if x is a String"
:added "1.0"
:static true}
string? (fn ^:static string? [x] (instance? String x)))
(def
^{:arglists '([x])
:doc "Return true if x implements IPersistentMap"
:added "1.0"
:static true}
map? (fn ^:static map? [x] (instance? clojure.lang.IPersistentMap x)))
(def
^{:arglists '([x])
:doc "Return true if x implements IPersistentVector"
:added "1.0"
:static true}
vector? (fn ^:static vector? [x] (instance? clojure.lang.IPersistentVector x)))
(def
^{:arglists '([map key val] [map key val & kvs])
:doc "assoc[iate]. When applied to a map, returns a new map of the
same (hashed/sorted) type, that contains the mapping of key(s) to
val(s). When applied to a vector, returns a new vector that
contains val at index. Note - index must be <= (count vector)."
:added "1.0"
:static true}
assoc
(fn ^:static assoc
([map key val] (. clojure.lang.RT (assoc map key val)))
([map key val & kvs]
(let [ret (assoc map key val)]
(if kvs
(if (next kvs)
(recur ret (first kvs) (second kvs) (nnext kvs))
(throw (IllegalArgumentException.
"assoc expects even number of arguments after map/vector, found odd number")))
ret)))))
;;;;;;;;;;;;;;;;; metadata ;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def
^{:arglists '([obj])
:doc "Returns the metadata of obj, returns nil if there is no metadata."
:added "1.0"
:static true}
meta (fn ^:static meta [x]
(if (instance? clojure.lang.IMeta x)
(. ^clojure.lang.IMeta x (meta)))))
(def
^{:arglists '([^clojure.lang.IObj obj m])
:doc "Returns an object of the same type and value as obj, with
map m as its metadata."
:added "1.0"
:static true}
with-meta (fn ^:static with-meta [^clojure.lang.IObj x m]
(. x (withMeta m))))
(def ^{:private true :dynamic true}
assert-valid-fdecl (fn [fdecl]))
(def
^{:private true}
sigs
(fn [fdecl]
(assert-valid-fdecl fdecl)
(let [asig
(fn [fdecl]
(let [arglist (first fdecl)
;elide implicit macro args
arglist (if (clojure.lang.Util/equals '&form (first arglist))
(clojure.lang.RT/subvec arglist 2 (clojure.lang.RT/count arglist))
arglist)
body (next fdecl)]
(if (map? (first body))
(if (next body)
(with-meta arglist (conj (if (meta arglist) (meta arglist) {}) (first body)))
arglist)
arglist)))]
(if (seq? (first fdecl))
(loop [ret [] fdecls fdecl]
(if fdecls
(recur (conj ret (asig (first fdecls))) (next fdecls))
(seq ret)))
(list (asig fdecl))))))
(def
^{:arglists '([coll])
:doc "Return the last item in coll, in linear time"
:added "1.0"
:static true}
last (fn ^:static last [s]
(if (next s)
(recur (next s))
(first s))))
(def
^{:arglists '([coll])
:doc "Return a seq of all but the last item in coll, in linear time"
:added "1.0"
:static true}
butlast (fn ^:static butlast [s]
(loop [ret [] s s]
(if (next s)
(recur (conj ret (first s)) (next s))
(seq ret)))))
(def
^{:doc "Same as (def name (fn [params* ] exprs*)) or (def
name (fn ([params* ] exprs*)+)) with any doc-string or attrs added
to the var metadata. prepost-map defines a map with optional keys
:pre and :post that contain collections of pre or post conditions."
:arglists '([name doc-string? attr-map? [params*] prepost-map? body]
[name doc-string? attr-map? ([params*] prepost-map? body)+ attr-map?])
:added "1.0"}
defn (fn defn [&form &env name & fdecl]
;; Note: Cannot delegate this check to def because of the call to (with-meta name ..)
(if (instance? clojure.lang.Symbol name)
nil
(throw (IllegalArgumentException. "First argument to defn must be a symbol")))
(let [m (if (string? (first fdecl))
{:doc (first fdecl)}
{})
fdecl (if (string? (first fdecl))
(next fdecl)
fdecl)
m (if (map? (first fdecl))
(conj m (first fdecl))
m)
fdecl (if (map? (first fdecl))
(next fdecl)
fdecl)
fdecl (if (vector? (first fdecl))
(list fdecl)
fdecl)
m (if (map? (last fdecl))
(conj m (last fdecl))
m)
fdecl (if (map? (last fdecl))
(butlast fdecl)
fdecl)
m (conj {:arglists (list 'quote (sigs fdecl))} m)
m (let [inline (:inline m)
ifn (first inline)
iname (second inline)]
;; same as: (if (and (= 'fn ifn) (not (symbol? iname))) ...)
(if (if (clojure.lang.Util/equiv 'fn ifn)
(if (instance? clojure.lang.Symbol iname) false true))
;; inserts the same fn name to the inline fn if it does not have one
(assoc m :inline (cons ifn (cons (clojure.lang.Symbol/intern (.concat (.getName ^clojure.lang.Symbol name) "__inliner"))
(next inline))))
m))
m (conj (if (meta name) (meta name) {}) m)]
(list 'def (with-meta name m)
;;todo - restore propagation of fn name
;;must figure out how to convey primitive hints to self calls first
(cons `fn fdecl) ))))
(. (var defn) (setMacro))
(defn to-array
"Returns an array of Objects containing the contents of coll, which
can be any Collection. Maps to java.util.Collection.toArray()."
{:tag "[Ljava.lang.Object;"
:added "1.0"
:static true}
[coll] (. clojure.lang.RT (toArray coll)))
(defn cast
"Throws a ClassCastException if x is not a c, else returns x."
{:added "1.0"
:static true}
[^Class c x]
(. c (cast x)))
(defn vector
"Creates a new vector containing the args."
{:added "1.0"
:static true}
([] [])
([a] [a])
([a b] [a b])
([a b c] [a b c])
([a b c d] [a b c d])
([a b c d & args]
(. clojure.lang.LazilyPersistentVector (create (cons a (cons b (cons c (cons d args))))))))
(defn vec
"Creates a new vector containing the contents of coll. Java arrays
will be aliased and should not be modified."
{:added "1.0"
:static true}
([coll]
(if (vector? coll)
(if (instance? clojure.lang.IObj coll)
(with-meta coll nil)
(clojure.lang.LazilyPersistentVector/create coll))
(clojure.lang.LazilyPersistentVector/create coll))))
(defn hash-map
"keyval => key val
Returns a new hash map with supplied mappings. If any keys are
equal, they are handled as if by repeated uses of assoc."
{:added "1.0"
:static true}
([] {})
([& keyvals]
(. clojure.lang.PersistentHashMap (create keyvals))))
(defn hash-set
"Returns a new hash set with supplied keys. Any equal keys are
handled as if by repeated uses of conj."
{:added "1.0"
:static true}
([] #{})
([& keys]
(clojure.lang.PersistentHashSet/create keys)))
(defn sorted-map
"keyval => key val
Returns a new sorted map with supplied mappings. If any keys are
equal, they are handled as if by repeated uses of assoc."
{:added "1.0"
:static true}
([& keyvals]
(clojure.lang.PersistentTreeMap/create keyvals)))
(defn sorted-map-by
"keyval => key val
Returns a new sorted map with supplied mappings, using the supplied
comparator. If any keys are equal, they are handled as if by
repeated uses of assoc."
{:added "1.0"
:static true}
([comparator & keyvals]
(clojure.lang.PersistentTreeMap/create comparator keyvals)))
(defn sorted-set
"Returns a new sorted set with supplied keys. Any equal keys are
handled as if by repeated uses of conj."
{:added "1.0"
:static true}
([& keys]
(clojure.lang.PersistentTreeSet/create keys)))
(defn sorted-set-by
"Returns a new sorted set with supplied keys, using the supplied
comparator. Any equal keys are handled as if by repeated uses of
conj."
{:added "1.1"
:static true}
([comparator & keys]
(clojure.lang.PersistentTreeSet/create comparator keys)))
;;;;;;;;;;;;;;;;;;;;
(defn nil?
"Returns true if x is nil, false otherwise."
{:tag Boolean
:added "1.0"
:static true
:inline (fn [x] (list 'clojure.lang.Util/identical x nil))}
[x] (clojure.lang.Util/identical x nil))
(def
^{:doc "Like defn, but the resulting function name is declared as a
macro and will be used as a macro by the compiler when it is
called."
:arglists '([name doc-string? attr-map? [params*] body]
[name doc-string? attr-map? ([params*] body)+ attr-map?])
:added "1.0"}
defmacro (fn [&form &env
name & args]
(let [prefix (loop [p (list name) args args]
(let [f (first args)]
(if (string? f)
(recur (cons f p) (next args))
(if (map? f)
(recur (cons f p) (next args))
p))))
fdecl (loop [fd args]
(if (string? (first fd))
(recur (next fd))
(if (map? (first fd))
(recur (next fd))
fd)))
fdecl (if (vector? (first fdecl))
(list fdecl)
fdecl)
add-implicit-args (fn [fd]
(let [args (first fd)]
(cons (vec (cons '&form (cons '&env args))) (next fd))))
add-args (fn [acc ds]
(if (nil? ds)
acc
(let [d (first ds)]
(if (map? d)
(conj acc d)
(recur (conj acc (add-implicit-args d)) (next ds))))))
fdecl (seq (add-args [] fdecl))
decl (loop [p prefix d fdecl]
(if p
(recur (next p) (cons (first p) d))
d))]
(list 'do
(cons `defn decl)
(list '. (list 'var name) '(setMacro))
(list 'var name)))))
(. (var defmacro) (setMacro))
(defmacro when
"Evaluates test. If logical true, evaluates body in an implicit do."
{:added "1.0"}
[test & body]
(list 'if test (cons 'do body)))
(defmacro when-not
"Evaluates test. If logical false, evaluates body in an implicit do."
{:added "1.0"}
[test & body]
(list 'if test nil (cons 'do body)))
(defn false?
"Returns true if x is the value false, false otherwise."
{:tag Boolean,
:added "1.0"
:static true}
[x] (clojure.lang.Util/identical x false))
(defn true?
"Returns true if x is the value true, false otherwise."
{:tag Boolean,
:added "1.0"
:static true}
[x] (clojure.lang.Util/identical x true))
(defn not
"Returns true if x is logical false, false otherwise."
{:tag Boolean
:added "1.0"
:static true}
[x] (if x false true))
(defn some?
"Returns true if x is not nil, false otherwise."
{:tag Boolean
:added "1.6"
:static true}
[x] (not (nil? x)))
(defn str
"With no args, returns the empty string. With one arg x, returns
x.toString(). (str nil) returns the empty string. With more than
one arg, returns the concatenation of the str values of the args."
{:tag String
:added "1.0"
:static true}
(^String [] "")
(^String [^Object x]
(if (nil? x) "" (. x (toString))))
(^String [x & ys]
((fn [^StringBuilder sb more]
(if more
(recur (. sb (append (str (first more)))) (next more))
(str sb)))
(new StringBuilder (str x)) ys)))
(defn symbol?
"Return true if x is a Symbol"
{:added "1.0"
:static true}
[x] (instance? clojure.lang.Symbol x))
(defn keyword?
"Return true if x is a Keyword"
{:added "1.0"
:static true}
[x] (instance? clojure.lang.Keyword x))
(defn symbol
"Returns a Symbol with the given namespace and name."
{:tag clojure.lang.Symbol
:added "1.0"
:static true}
([name] (if (symbol? name) name (clojure.lang.Symbol/intern name)))
([ns name] (clojure.lang.Symbol/intern ns name)))
(defn gensym
"Returns a new symbol with a unique name. If a prefix string is
supplied, the name is prefix# where # is some unique number. If
prefix is not supplied, the prefix is 'G__'."
{:added "1.0"
:static true}
([] (gensym "G__"))
([prefix-string] (. clojure.lang.Symbol (intern (str prefix-string (str (. clojure.lang.RT (nextID))))))))
(defmacro cond
"Takes a set of test/expr pairs. It evaluates each test one at a
time. If a test returns logical true, cond evaluates and returns
the value of the corresponding expr and doesn't evaluate any of the
other tests or exprs. (cond) returns nil."
{:added "1.0"}
[& clauses]
(when clauses
(list 'if (first clauses)
(if (next clauses)
(second clauses)
(throw (IllegalArgumentException.
"cond requires an even number of forms")))
(cons 'clojure.core/cond (next (next clauses))))))
(defn keyword
"Returns a Keyword with the given namespace and name. Do not use :
in the keyword strings, it will be added automatically."
{:tag clojure.lang.Keyword
:added "1.0"
:static true}
([name] (cond (keyword? name) name
(symbol? name) (clojure.lang.Keyword/intern ^clojure.lang.Symbol name)
(string? name) (clojure.lang.Keyword/intern ^String name)))
([ns name] (clojure.lang.Keyword/intern ns name)))
(defn find-keyword
"Returns a Keyword with the given namespace and name if one already
exists. This function will not intern a new keyword. If the keyword
has not already been interned, it will return nil. Do not use :
in the keyword strings, it will be added automatically."
{:tag clojure.lang.Keyword
:added "1.3"
:static true}
([name] (cond (keyword? name) name
(symbol? name) (clojure.lang.Keyword/find ^clojure.lang.Symbol name)
(string? name) (clojure.lang.Keyword/find ^String name)))
([ns name] (clojure.lang.Keyword/find ns name)))
(defn spread
{:private true
:static true}
[arglist]
(cond
(nil? arglist) nil
(nil? (next arglist)) (seq (first arglist))
:else (cons (first arglist) (spread (next arglist)))))
(defn list*
"Creates a new list containing the items prepended to the rest, the
last of which will be treated as a sequence."
{:added "1.0"
:static true}
([args] (seq args))
([a args] (cons a args))
([a b args] (cons a (cons b args)))
([a b c args] (cons a (cons b (cons c args))))
([a b c d & more]
(cons a (cons b (cons c (cons d (spread more)))))))
(defn apply
"Applies fn f to the argument list formed by prepending intervening arguments to args."
{:added "1.0"
:static true}
([^clojure.lang.IFn f args]
(. f (applyTo (seq args))))
([^clojure.lang.IFn f x args]
(. f (applyTo (list* x args))))
([^clojure.lang.IFn f x y args]
(. f (applyTo (list* x y args))))
([^clojure.lang.IFn f x y z args]
(. f (applyTo (list* x y z args))))
([^clojure.lang.IFn f a b c d & args]
(. f (applyTo (cons a (cons b (cons c (cons d (spread args)))))))))
(defn vary-meta
"Returns an object of the same type and value as obj, with
(apply f (meta obj) args) as its metadata."
{:added "1.0"
:static true}
[obj f & args]
(with-meta obj (apply f (meta obj) args)))
(defmacro lazy-seq
"Takes a body of expressions that returns an ISeq or nil, and yields
a Seqable object that will invoke the body only the first time seq
is called, and will cache the result and return it on all subsequent
seq calls. See also - realized?"
{:added "1.0"}
[& body]
(list 'new 'clojure.lang.LazySeq (list* '^{:once true} fn* [] body)))
(defn ^:static ^clojure.lang.ChunkBuffer chunk-buffer ^clojure.lang.ChunkBuffer [capacity]
(clojure.lang.ChunkBuffer. capacity))
(defn ^:static chunk-append [^clojure.lang.ChunkBuffer b x]
(.add b x))
(defn ^:static ^clojure.lang.IChunk chunk [^clojure.lang.ChunkBuffer b]
(.chunk b))
(defn ^:static ^clojure.lang.IChunk chunk-first ^clojure.lang.IChunk [^clojure.lang.IChunkedSeq s]
(.chunkedFirst s))
(defn ^:static ^clojure.lang.ISeq chunk-rest ^clojure.lang.ISeq [^clojure.lang.IChunkedSeq s]
(.chunkedMore s))
(defn ^:static ^clojure.lang.ISeq chunk-next ^clojure.lang.ISeq [^clojure.lang.IChunkedSeq s]
(.chunkedNext s))
(defn ^:static chunk-cons [chunk rest]
(if (clojure.lang.Numbers/isZero (clojure.lang.RT/count chunk))
rest
(clojure.lang.ChunkedCons. chunk rest)))
(defn ^:static chunked-seq? [s]
(instance? clojure.lang.IChunkedSeq s))
(defn concat
"Returns a lazy seq representing the concatenation of the elements in the supplied colls."
{:added "1.0"
:static true}
([] (lazy-seq nil))
([x] (lazy-seq x))
([x y]
(lazy-seq
(let [s (seq x)]
(if s
(if (chunked-seq? s)
(chunk-cons (chunk-first s) (concat (chunk-rest s) y))
(cons (first s) (concat (rest s) y)))
y))))
([x y & zs]
(let [cat (fn cat [xys zs]
(lazy-seq
(let [xys (seq xys)]
(if xys
(if (chunked-seq? xys)
(chunk-cons (chunk-first xys)
(cat (chunk-rest xys) zs))
(cons (first xys) (cat (rest xys) zs)))
(when zs
(cat (first zs) (next zs)))))))]
(cat (concat x y) zs))))
;;;;;;;;;;;;;;;;at this point all the support for syntax-quote exists;;;;;;;;;;;;;;;;;;;;;;
(defmacro delay
"Takes a body of expressions and yields a Delay object that will
invoke the body only the first time it is forced (with force or deref/@), and
will cache the result and return it on all subsequent force
calls. See also - realized?"
{:added "1.0"}
[& body]
(list 'new 'clojure.lang.Delay (list* `^{:once true} fn* [] body)))
(defn delay?
"returns true if x is a Delay created with delay"
{:added "1.0"
:static true}
[x] (instance? clojure.lang.Delay x))
(defn force
"If x is a Delay, returns the (possibly cached) value of its expression, else returns x"
{:added "1.0"
:static true}
[x] (. clojure.lang.Delay (force x)))
(defmacro if-not
"Evaluates test. If logical false, evaluates and returns then expr,
otherwise else expr, if supplied, else nil."
{:added "1.0"}
([test then] `(if-not ~test ~then nil))
([test then else]
`(if (not ~test) ~then ~else)))
(defn identical?
"Tests if 2 arguments are the same object"
{:inline (fn [x y] `(. clojure.lang.Util identical ~x ~y))
:inline-arities #{2}
:added "1.0"}
([x y] (clojure.lang.Util/identical x y)))
;equiv-based
(defn =
"Equality. Returns true if x equals y, false if not. Same as
Java x.equals(y) except it also works for nil, and compares
numbers and collections in a type-independent manner. Clojure's immutable data
structures define equals() (and thus =) as a value, not an identity,
comparison."
{:inline (fn [x y] `(. clojure.lang.Util equiv ~x ~y))
:inline-arities #{2}
:added "1.0"}
([x] true)
([x y] (clojure.lang.Util/equiv x y))
([x y & more]
(if (clojure.lang.Util/equiv x y)
(if (next more)
(recur y (first more) (next more))
(clojure.lang.Util/equiv y (first more)))
false)))
;equals-based
#_(defn =
"Equality. Returns true if x equals y, false if not. Same as Java
x.equals(y) except it also works for nil. Boxed numbers must have
same type. Clojure's immutable data structures define equals() (and
thus =) as a value, not an identity, comparison."
{:inline (fn [x y] `(. clojure.lang.Util equals ~x ~y))
:inline-arities #{2}
:added "1.0"}
([x] true)
([x y] (clojure.lang.Util/equals x y))
([x y & more]
(if (= x y)
(if (next more)
(recur y (first more) (next more))
(= y (first more)))
false)))
(defn not=
"Same as (not (= obj1 obj2))"
{:tag Boolean
:added "1.0"
:static true}
([x] false)
([x y] (not (= x y)))
([x y & more]
(not (apply = x y more))))
(defn compare
"Comparator. Returns a negative number, zero, or a positive number
when x is logically 'less than', 'equal to', or 'greater than'
y. Same as Java x.compareTo(y) except it also works for nil, and
compares numbers and collections in a type-independent manner. x
must implement Comparable"
{
:inline (fn [x y] `(. clojure.lang.Util compare ~x ~y))
:added "1.0"}
[x y] (. clojure.lang.Util (compare x y)))
(defmacro and
"Evaluates exprs one at a time, from left to right. If a form
returns logical false (nil or false), and returns that value and
doesn't evaluate any of the other expressions, otherwise it returns
the value of the last expr. (and) returns true."
{:added "1.0"}
([] true)
([x] x)
([x & next]
`(let [and# ~x]
(if and# (and ~@next) and#))))
(defmacro or
"Evaluates exprs one at a time, from left to right. If a form
returns a logical true value, or returns that value and doesn't
evaluate any of the other expressions, otherwise it returns the
value of the last expression. (or) returns nil."
{:added "1.0"}
([] nil)
([x] x)
([x & next]
`(let [or# ~x]
(if or# or# (or ~@next)))))
;;;;;;;;;;;;;;;;;;; sequence fns ;;;;;;;;;;;;;;;;;;;;;;;
(defn zero?
"Returns true if num is zero, else false"
{
:inline (fn [x] `(. clojure.lang.Numbers (isZero ~x)))
:added "1.0"}
[x] (. clojure.lang.Numbers (isZero x)))
(defn count
"Returns the number of items in the collection. (count nil) returns
0. Also works on strings, arrays, and Java Collections and Maps"
{
:inline (fn [x] `(. clojure.lang.RT (count ~x)))
:added "1.0"}
[coll] (clojure.lang.RT/count coll))
(defn int
"Coerce to int"
{
:inline (fn [x] `(. clojure.lang.RT (~(if *unchecked-math* 'uncheckedIntCast 'intCast) ~x)))
:added "1.0"}
[x] (. clojure.lang.RT (intCast x)))
(defn nth
"Returns the value at the index. get returns nil if index out of
bounds, nth throws an exception unless not-found is supplied. nth
also works for strings, Java arrays, regex Matchers and Lists, and,
in O(n) time, for sequences."
{:inline (fn [c i & nf] `(. clojure.lang.RT (nth ~c ~i ~@nf)))
:inline-arities #{2 3}
:added "1.0"}
([coll index] (. clojure.lang.RT (nth coll index)))
([coll index not-found] (. clojure.lang.RT (nth coll index not-found))))
(defn <
"Returns non-nil if nums are in monotonically increasing order,
otherwise false."
{:inline (fn [x y] `(. clojure.lang.Numbers (lt ~x ~y)))
:inline-arities #{2}
:added "1.0"}
([x] true)
([x y] (. clojure.lang.Numbers (lt x y)))
([x y & more]
(if (< x y)
(if (next more)
(recur y (first more) (next more))
(< y (first more)))
false)))
(defn inc'
"Returns a number one greater than num. Supports arbitrary precision.
See also: inc"
{:inline (fn [x] `(. clojure.lang.Numbers (incP ~x)))
:added "1.0"}
[x] (. clojure.lang.Numbers (incP x)))
(defn inc
"Returns a number one greater than num. Does not auto-promote
longs, will throw on overflow. See also: inc'"
{:inline (fn [x] `(. clojure.lang.Numbers (~(if *unchecked-math* 'unchecked_inc 'inc) ~x)))
:added "1.2"}
[x] (. clojure.lang.Numbers (inc x)))
;; reduce is defined again later after InternalReduce loads
(defn ^:private ^:static
reduce1
([f coll]
(let [s (seq coll)]
(if s
(reduce1 f (first s) (next s))
(f))))
([f val coll]
(let [s (seq coll)]
(if s
(if (chunked-seq? s)
(recur f
(.reduce (chunk-first s) f val)
(chunk-next s))
(recur f (f val (first s)) (next s)))
val))))
(defn reverse
"Returns a seq of the items in coll in reverse order. Not lazy."
{:added "1.0"
:static true}
[coll]
(reduce1 conj () coll))
;;math stuff
(defn ^:private nary-inline
([op] (nary-inline op op))
([op unchecked-op]
(fn
([x] (let [op (if *unchecked-math* unchecked-op op)]
`(. clojure.lang.Numbers (~op ~x))))
([x y] (let [op (if *unchecked-math* unchecked-op op)]
`(. clojure.lang.Numbers (~op ~x ~y))))
([x y & more]
(let [op (if *unchecked-math* unchecked-op op)]
(reduce1
(fn [a b] `(. clojure.lang.Numbers (~op ~a ~b)))
`(. clojure.lang.Numbers (~op ~x ~y)) more))))))
(defn ^:private >1? [n] (clojure.lang.Numbers/gt n 1))
(defn ^:private >0? [n] (clojure.lang.Numbers/gt n 0))
(defn +'
"Returns the sum of nums. (+) returns 0. Supports arbitrary precision.
See also: +"
{:inline (nary-inline 'addP)
:inline-arities >1?
:added "1.0"}
([] 0)
([x] (cast Number x))
([x y] (. clojure.lang.Numbers (addP x y)))
([x y & more]
(reduce1 +' (+' x y) more)))
(defn +
"Returns the sum of nums. (+) returns 0. Does not auto-promote
longs, will throw on overflow. See also: +'"
{:inline (nary-inline 'add 'unchecked_add)
:inline-arities >1?
:added "1.2"}
([] 0)
([x] (cast Number x))
([x y] (. clojure.lang.Numbers (add x y)))
([x y & more]
(reduce1 + (+ x y) more)))
(defn *'
"Returns the product of nums. (*) returns 1. Supports arbitrary precision.
See also: *"
{:inline (nary-inline 'multiplyP)
:inline-arities >1?
:added "1.0"}
([] 1)
([x] (cast Number x))
([x y] (. clojure.lang.Numbers (multiplyP x y)))
([x y & more]
(reduce1 *' (*' x y) more)))
(defn *
"Returns the product of nums. (*) returns 1. Does not auto-promote
longs, will throw on overflow. See also: *'"
{:inline (nary-inline 'multiply 'unchecked_multiply)
:inline-arities >1?
:added "1.2"}
([] 1)
([x] (cast Number x))
([x y] (. clojure.lang.Numbers (multiply x y)))
([x y & more]
(reduce1 * (* x y) more)))
(defn /
"If no denominators are supplied, returns 1/numerator,
else returns numerator divided by all of the denominators."
{:inline (nary-inline 'divide)
:inline-arities >1?
:added "1.0"}
([x] (/ 1 x))
([x y] (. clojure.lang.Numbers (divide x y)))
([x y & more]
(reduce1 / (/ x y) more)))
(defn -'
"If no ys are supplied, returns the negation of x, else subtracts
the ys from x and returns the result. Supports arbitrary precision.
See also: -"
{:inline (nary-inline 'minusP)
:inline-arities >0?
:added "1.0"}
([x] (. clojure.lang.Numbers (minusP x)))
([x y] (. clojure.lang.Numbers (minusP x y)))
([x y & more]
(reduce1 -' (-' x y) more)))
(defn -
"If no ys are supplied, returns the negation of x, else subtracts
the ys from x and returns the result. Does not auto-promote
longs, will throw on overflow. See also: -'"
{:inline (nary-inline 'minus 'unchecked_minus)
:inline-arities >0?
:added "1.2"}
([x] (. clojure.lang.Numbers (minus x)))
([x y] (. clojure.lang.Numbers (minus x y)))
([x y & more]
(reduce1 - (- x y) more)))
(defn <=
"Returns non-nil if nums are in monotonically non-decreasing order,
otherwise false."
{:inline (fn [x y] `(. clojure.lang.Numbers (lte ~x ~y)))
:inline-arities #{2}
:added "1.0"}
([x] true)
([x y] (. clojure.lang.Numbers (lte x y)))
([x y & more]
(if (<= x y)
(if (next more)
(recur y (first more) (next more))
(<= y (first more)))
false)))
(defn >
"Returns non-nil if nums are in monotonically decreasing order,
otherwise false."
{:inline (fn [x y] `(. clojure.lang.Numbers (gt ~x ~y)))
:inline-arities #{2}
:added "1.0"}
([x] true)
([x y] (. clojure.lang.Numbers (gt x y)))
([x y & more]
(if (> x y)
(if (next more)
(recur y (first more) (next more))
(> y (first more)))
false)))
(defn >=
"Returns non-nil if nums are in monotonically non-increasing order,
otherwise false."
{:inline (fn [x y] `(. clojure.lang.Numbers (gte ~x ~y)))
:inline-arities #{2}
:added "1.0"}
([x] true)
([x y] (. clojure.lang.Numbers (gte x y)))
([x y & more]
(if (>= x y)
(if (next more)
(recur y (first more) (next more))
(>= y (first more)))
false)))
(defn ==
"Returns non-nil if nums all have the equivalent
value (type-independent), otherwise false"
{:inline (fn [x y] `(. clojure.lang.Numbers (equiv ~x ~y)))
:inline-arities #{2}
:added "1.0"}
([x] true)
([x y] (. clojure.lang.Numbers (equiv x y)))
([x y & more]
(if (== x y)
(if (next more)
(recur y (first more) (next more))
(== y (first more)))
false)))
(defn max
"Returns the greatest of the nums."
{:added "1.0"
:inline-arities >1?
:inline (nary-inline 'max)}
([x] x)
([x y] (. clojure.lang.Numbers (max x y)))
([x y & more]
(reduce1 max (max x y) more)))
(defn min
"Returns the least of the nums."
{:added "1.0"
:inline-arities >1?
:inline (nary-inline 'min)}
([x] x)
([x y] (. clojure.lang.Numbers (min x y)))
([x y & more]
(reduce1 min (min x y) more)))
(defn dec'
"Returns a number one less than num. Supports arbitrary precision.
See also: dec"
{:inline (fn [x] `(. clojure.lang.Numbers (decP ~x)))
:added "1.0"}
[x] (. clojure.lang.Numbers (decP x)))
(defn dec
"Returns a number one less than num. Does not auto-promote
longs, will throw on overflow. See also: dec'"
{:inline (fn [x] `(. clojure.lang.Numbers (~(if *unchecked-math* 'unchecked_dec 'dec) ~x)))
:added "1.2"}
[x] (. clojure.lang.Numbers (dec x)))
(defn unchecked-inc-int
"Returns a number one greater than x, an int.
Note - uses a primitive operator subject to overflow."
{:inline (fn [x] `(. clojure.lang.Numbers (unchecked_int_inc ~x)))
:added "1.0"}
[x] (. clojure.lang.Numbers (unchecked_int_inc x)))
(defn unchecked-inc
"Returns a number one greater than x, a long.
Note - uses a primitive operator subject to overflow."
{:inline (fn [x] `(. clojure.lang.Numbers (unchecked_inc ~x)))
:added "1.0"}
[x] (. clojure.lang.Numbers (unchecked_inc x)))
(defn unchecked-dec-int
"Returns a number one less than x, an int.
Note - uses a primitive operator subject to overflow."
{:inline (fn [x] `(. clojure.lang.Numbers (unchecked_int_dec ~x)))
:added "1.0"}
[x] (. clojure.lang.Numbers (unchecked_int_dec x)))
(defn unchecked-dec
"Returns a number one less than x, a long.
Note - uses a primitive operator subject to overflow."
{:inline (fn [x] `(. clojure.lang.Numbers (unchecked_dec ~x)))
:added "1.0"}
[x] (. clojure.lang.Numbers (unchecked_dec x)))
(defn unchecked-negate-int
"Returns the negation of x, an int.
Note - uses a primitive operator subject to overflow."
{:inline (fn [x] `(. clojure.lang.Numbers (unchecked_int_negate ~x)))
:added "1.0"}
[x] (. clojure.lang.Numbers (unchecked_int_negate x)))
(defn unchecked-negate
"Returns the negation of x, a long.
Note - uses a primitive operator subject to overflow."
{:inline (fn [x] `(. clojure.lang.Numbers (unchecked_minus ~x)))
:added "1.0"}
[x] (. clojure.lang.Numbers (unchecked_minus x)))
(defn unchecked-add-int
"Returns the sum of x and y, both int.
Note - uses a primitive operator subject to overflow."
{:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_int_add ~x ~y)))
:added "1.0"}
[x y] (. clojure.lang.Numbers (unchecked_int_add x y)))
(defn unchecked-add
"Returns the sum of x and y, both long.
Note - uses a primitive operator subject to overflow."
{:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_add ~x ~y)))
:added "1.0"}
[x y] (. clojure.lang.Numbers (unchecked_add x y)))
(defn unchecked-subtract-int
"Returns the difference of x and y, both int.
Note - uses a primitive operator subject to overflow."
{:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_int_subtract ~x ~y)))
:added "1.0"}
[x y] (. clojure.lang.Numbers (unchecked_int_subtract x y)))
(defn unchecked-subtract
"Returns the difference of x and y, both long.
Note - uses a primitive operator subject to overflow."
{:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_minus ~x ~y)))
:added "1.0"}
[x y] (. clojure.lang.Numbers (unchecked_minus x y)))
(defn unchecked-multiply-int
"Returns the product of x and y, both int.
Note - uses a primitive operator subject to overflow."
{:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_int_multiply ~x ~y)))
:added "1.0"}
[x y] (. clojure.lang.Numbers (unchecked_int_multiply x y)))
(defn unchecked-multiply
"Returns the product of x and y, both long.
Note - uses a primitive operator subject to overflow."
{:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_multiply ~x ~y)))
:added "1.0"}
[x y] (. clojure.lang.Numbers (unchecked_multiply x y)))
(defn unchecked-divide-int
"Returns the division of x by y, both int.
Note - uses a primitive operator subject to truncation."
{:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_int_divide ~x ~y)))
:added "1.0"}
[x y] (. clojure.lang.Numbers (unchecked_int_divide x y)))
(defn unchecked-remainder-int
"Returns the remainder of division of x by y, both int.
Note - uses a primitive operator subject to truncation."
{:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_int_remainder ~x ~y)))
:added "1.0"}
[x y] (. clojure.lang.Numbers (unchecked_int_remainder x y)))
(defn pos?
"Returns true if num is greater than zero, else false"
{
:inline (fn [x] `(. clojure.lang.Numbers (isPos ~x)))
:added "1.0"}
[x] (. clojure.lang.Numbers (isPos x)))
(defn neg?
"Returns true if num is less than zero, else false"
{
:inline (fn [x] `(. clojure.lang.Numbers (isNeg ~x)))
:added "1.0"}
[x] (. clojure.lang.Numbers (isNeg x)))
(defn quot
"quot[ient] of dividing numerator by denominator."
{:added "1.0"
:static true
:inline (fn [x y] `(. clojure.lang.Numbers (quotient ~x ~y)))}
[num div]
(. clojure.lang.Numbers (quotient num div)))
(defn rem
"remainder of dividing numerator by denominator."
{:added "1.0"
:static true
:inline (fn [x y] `(. clojure.lang.Numbers (remainder ~x ~y)))}
[num div]
(. clojure.lang.Numbers (remainder num div)))
(defn rationalize
"returns the rational value of num"
{:added "1.0"
:static true}
[num]
(. clojure.lang.Numbers (rationalize num)))
;;Bit ops
(defn bit-not
"Bitwise complement"
{:inline (fn [x] `(. clojure.lang.Numbers (not ~x)))
:added "1.0"}
[x] (. clojure.lang.Numbers not x))
(defn bit-and
"Bitwise and"
{:inline (nary-inline 'and)
:inline-arities >1?
:added "1.0"}
([x y] (. clojure.lang.Numbers and x y))
([x y & more]
(reduce1 bit-and (bit-and x y) more)))
(defn bit-or
"Bitwise or"
{:inline (nary-inline 'or)
:inline-arities >1?
:added "1.0"}
([x y] (. clojure.lang.Numbers or x y))
([x y & more]
(reduce1 bit-or (bit-or x y) more)))
(defn bit-xor
"Bitwise exclusive or"
{:inline (nary-inline 'xor)
:inline-arities >1?
:added "1.0"}
([x y] (. clojure.lang.Numbers xor x y))
([x y & more]
(reduce1 bit-xor (bit-xor x y) more)))
(defn bit-and-not
"Bitwise and with complement"
{:inline (nary-inline 'andNot)
:inline-arities >1?
:added "1.0"
:static true}
([x y] (. clojure.lang.Numbers andNot x y))
([x y & more]
(reduce1 bit-and-not (bit-and-not x y) more)))
(defn bit-clear
"Clear bit at index n"
{:added "1.0"
:static true}
[x n] (. clojure.lang.Numbers clearBit x n))
(defn bit-set
"Set bit at index n"
{:added "1.0"
:static true}
[x n] (. clojure.lang.Numbers setBit x n))
(defn bit-flip
"Flip bit at index n"
{:added "1.0"
:static true}
[x n] (. clojure.lang.Numbers flipBit x n))
(defn bit-test
"Test bit at index n"
{:added "1.0"
:static true}
[x n] (. clojure.lang.Numbers testBit x n))
(defn bit-shift-left
"Bitwise shift left"
{:inline (fn [x n] `(. clojure.lang.Numbers (shiftLeft ~x ~n)))
:added "1.0"}
[x n] (. clojure.lang.Numbers shiftLeft x n))
(defn bit-shift-right
"Bitwise shift right"
{:inline (fn [x n] `(. clojure.lang.Numbers (shiftRight ~x ~n)))
:added "1.0"}
[x n] (. clojure.lang.Numbers shiftRight x n))
(defn unsigned-bit-shift-right
"Bitwise shift right, without sign-extension."
{:inline (fn [x n] `(. clojure.lang.Numbers (unsignedShiftRight ~x ~n)))
:added "1.6"}
[x n] (. clojure.lang.Numbers unsignedShiftRight x n))
(defn integer?
"Returns true if n is an integer"
{:added "1.0"
:static true}
[n]
(or (instance? Integer n)
(instance? Long n)
(instance? clojure.lang.BigInt n)
(instance? BigInteger n)
(instance? Short n)
(instance? Byte n)))
(defn even?
"Returns true if n is even, throws an exception if n is not an integer"
{:added "1.0"
:static true}
[n] (if (integer? n)
(zero? (bit-and (clojure.lang.RT/uncheckedLongCast n) 1))
(throw (IllegalArgumentException. (str "Argument must be an integer: " n)))))
(defn odd?
"Returns true if n is odd, throws an exception if n is not an integer"
{:added "1.0"
:static true}
[n] (not (even? n)))
;;
(defn complement
"Takes a fn f and returns a fn that takes the same arguments as f,
has the same effects, if any, and returns the opposite truth value."
{:added "1.0"
:static true}
[f]
(fn
([] (not (f)))
([x] (not (f x)))
([x y] (not (f x y)))
([x y & zs] (not (apply f x y zs)))))
(defn constantly
"Returns a function that takes any number of arguments and returns x."
{:added "1.0"
:static true}
[x] (fn [& args] x))
(defn identity
"Returns its argument."
{:added "1.0"
:static true}
[x] x)
;;Collection stuff
;;list stuff
(defn peek
"For a list or queue, same as first, for a vector, same as, but much
more efficient than, last. If the collection is empty, returns nil."
{:added "1.0"
:static true}
[coll] (. clojure.lang.RT (peek coll)))
(defn pop
"For a list or queue, returns a new list/queue without the first
item, for a vector, returns a new vector without the last item. If
the collection is empty, throws an exception. Note - not the same
as next/butlast."
{:added "1.0"
:static true}
[coll] (. clojure.lang.RT (pop coll)))
;;map stuff
(defn contains?
"Returns true if key is present in the given collection, otherwise
returns false. Note that for numerically indexed collections like
vectors and Java arrays, this tests if the numeric key is within the
range of indexes. 'contains?' operates constant or logarithmic time;
it will not perform a linear search for a value. See also 'some'."
{:added "1.0"
:static true}
[coll key] (. clojure.lang.RT (contains coll key)))
(defn get
"Returns the value mapped to key, not-found or nil if key not present."
{:inline (fn [m k & nf] `(. clojure.lang.RT (get ~m ~k ~@nf)))
:inline-arities #{2 3}
:added "1.0"}
([map key]
(. clojure.lang.RT (get map key)))
([map key not-found]
(. clojure.lang.RT (get map key not-found))))
(defn dissoc
"dissoc[iate]. Returns a new map of the same (hashed/sorted) type,
that does not contain a mapping for key(s)."
{:added "1.0"
:static true}
([map] map)
([map key]
(. clojure.lang.RT (dissoc map key)))
([map key & ks]
(let [ret (dissoc map key)]
(if ks
(recur ret (first ks) (next ks))
ret))))
(defn disj
"disj[oin]. Returns a new set of the same (hashed/sorted) type, that
does not contain key(s)."
{:added "1.0"
:static true}
([set] set)
([^clojure.lang.IPersistentSet set key]
(when set
(. set (disjoin key))))
([set key & ks]
(when set
(let [ret (disj set key)]
(if ks
(recur ret (first ks) (next ks))
ret)))))
(defn find
"Returns the map entry for key, or nil if key not present."
{:added "1.0"
:static true}
[map key] (. clojure.lang.RT (find map key)))
(defn select-keys
"Returns a map containing only those entries in map whose key is in keys"
{:added "1.0"
:static true}
[map keyseq]
(loop [ret {} keys (seq keyseq)]
(if keys
(let [entry (. clojure.lang.RT (find map (first keys)))]
(recur
(if entry
(conj ret entry)
ret)
(next keys)))
(with-meta ret (meta map)))))
(defn keys
"Returns a sequence of the map's keys, in the same order as (seq map)."
{:added "1.0"
:static true}
[map] (. clojure.lang.RT (keys map)))
(defn vals
"Returns a sequence of the map's values, in the same order as (seq map)."
{:added "1.0"
:static true}
[map] (. clojure.lang.RT (vals map)))
(defn key
"Returns the key of the map entry."
{:added "1.0"
:static true}
[^java.util.Map$Entry e]
(. e (getKey)))
(defn val
"Returns the value in the map entry."
{:added "1.0"
:static true}
[^java.util.Map$Entry e]
(. e (getValue)))
(defn rseq
"Returns, in constant time, a seq of the items in rev (which
can be a vector or sorted-map), in reverse order. If rev is empty returns nil"
{:added "1.0"
:static true}
[^clojure.lang.Reversible rev]
(. rev (rseq)))
(defn name
"Returns the name String of a string, symbol or keyword."
{:tag String
:added "1.0"
:static true}
[x]
(if (string? x) x (. ^clojure.lang.Named x (getName))))
(defn namespace
"Returns the namespace String of a symbol or keyword, or nil if not present."
{:tag String
:added "1.0"
:static true}
[^clojure.lang.Named x]
(. x (getNamespace)))
(defmacro locking
"Executes exprs in an implicit do, while holding the monitor of x.
Will release the monitor of x in all circumstances."
{:added "1.0"}
[x & body]
`(let [lockee# ~x]
(try
(monitor-enter lockee#)
~@body
(finally
(monitor-exit lockee#)))))
(defmacro ..
"form => fieldName-symbol or (instanceMethodName-symbol args*)
Expands into a member access (.) of the first member on the first
argument, followed by the next member on the result, etc. For
instance:
(.. System (getProperties) (get \"os.name\"))
expands to:
(. (. System (getProperties)) (get \"os.name\"))
but is easier to write, read, and understand."
{:added "1.0"}
([x form] `(. ~x ~form))
([x form & more] `(.. (. ~x ~form) ~@more)))
(defmacro ->
"Threads the expr through the forms. Inserts x as the
second item in the first form, making a list of it if it is not a
list already. If there are more forms, inserts the first form as the
second item in second form, etc."
{:added "1.0"}
[x & forms]
(loop [x x, forms forms]
(if forms
(let [form (first forms)
threaded (if (seq? form)
(with-meta `(~(first form) ~x ~@(next form)) (meta form))
(list form x))]
(recur threaded (next forms)))
x)))
(defmacro ->>
"Threads the expr through the forms. Inserts x as the
last item in the first form, making a list of it if it is not a
list already. If there are more forms, inserts the first form as the
last item in second form, etc."
{:added "1.1"}
[x & forms]
(loop [x x, forms forms]
(if forms
(let [form (first forms)
threaded (if (seq? form)
(with-meta `(~(first form) ~@(next form) ~x) (meta form))
(list form x))]
(recur threaded (next forms)))
x)))
(def map)
(defn ^:private check-valid-options
"Throws an exception if the given option map contains keys not listed
as valid, else returns nil."
[options & valid-keys]
(when (seq (apply disj (apply hash-set (keys options)) valid-keys))
(throw
(IllegalArgumentException.
(apply str "Only these options are valid: "
(first valid-keys)
(map #(str ", " %) (rest valid-keys)))))))
;;multimethods
(def global-hierarchy)
(defmacro defmulti
"Creates a new multimethod with the associated dispatch function.
The docstring and attr-map are optional.
Options are key-value pairs and may be one of:
:default
The default dispatch value, defaults to :default
:hierarchy
The value used for hierarchical dispatch (e.g. ::square is-a ::shape)
Hierarchies are type-like relationships that do not depend upon type
inheritance. By default Clojure's multimethods dispatch off of a
global hierarchy map. However, a hierarchy relationship can be
created with the derive function used to augment the root ancestor
created with make-hierarchy.
Multimethods expect the value of the hierarchy option to be supplied as
a reference type e.g. a var (i.e. via the Var-quote dispatch macro #'
or the var special form)."
{:arglists '([name docstring? attr-map? dispatch-fn & options])
:added "1.0"}
[mm-name & options]
(let [docstring (if (string? (first options))
(first options)
nil)
options (if (string? (first options))
(next options)
options)
m (if (map? (first options))
(first options)
{})
options (if (map? (first options))
(next options)
options)
dispatch-fn (first options)
options (next options)
m (if docstring
(assoc m :doc docstring)
m)
m (if (meta mm-name)
(conj (meta mm-name) m)
m)]
(when (= (count options) 1)
(throw (Exception. "The syntax for defmulti has changed. Example: (defmulti name dispatch-fn :default dispatch-value)")))
(let [options (apply hash-map options)
default (get options :default :default)
hierarchy (get options :hierarchy #'global-hierarchy)]
(check-valid-options options :default :hierarchy)
`(let [v# (def ~mm-name)]
(when-not (and (.hasRoot v#) (instance? clojure.lang.MultiFn (deref v#)))
(def ~(with-meta mm-name m)
(new clojure.lang.MultiFn ~(name mm-name) ~dispatch-fn ~default ~hierarchy)))))))
(defmacro defmethod
"Creates and installs a new method of multimethod associated with dispatch-value. "
{:added "1.0"}
[multifn dispatch-val & fn-tail]
`(. ~(with-meta multifn {:tag 'clojure.lang.MultiFn}) addMethod ~dispatch-val (fn ~@fn-tail)))
(defn remove-all-methods
"Removes all of the methods of multimethod."
{:added "1.2"
:static true}
[^clojure.lang.MultiFn multifn]
(.reset multifn))
(defn remove-method
"Removes the method of multimethod associated with dispatch-value."
{:added "1.0"
:static true}
[^clojure.lang.MultiFn multifn dispatch-val]
(. multifn removeMethod dispatch-val))
(defn prefer-method
"Causes the multimethod to prefer matches of dispatch-val-x over dispatch-val-y
when there is a conflict"
{:added "1.0"
:static true}
[^clojure.lang.MultiFn multifn dispatch-val-x dispatch-val-y]
(. multifn preferMethod dispatch-val-x dispatch-val-y))
(defn methods
"Given a multimethod, returns a map of dispatch values -> dispatch fns"
{:added "1.0"
:static true}
[^clojure.lang.MultiFn multifn] (.getMethodTable multifn))
(defn get-method
"Given a multimethod and a dispatch value, returns the dispatch fn
that would apply to that value, or nil if none apply and no default"
{:added "1.0"
:static true}
[^clojure.lang.MultiFn multifn dispatch-val] (.getMethod multifn dispatch-val))
(defn prefers
"Given a multimethod, returns a map of preferred value -> set of other values"
{:added "1.0"
:static true}
[^clojure.lang.MultiFn multifn] (.getPreferTable multifn))
;;;;;;;;; var stuff
(defmacro ^{:private true} assert-args
[& pairs]
`(do (when-not ~(first pairs)
(throw (IllegalArgumentException.
(str (first ~'&form) " requires " ~(second pairs) " in " ~'*ns* ":" (:line (meta ~'&form))))))
~(let [more (nnext pairs)]
(when more
(list* `assert-args more)))))
(defmacro if-let
"bindings => binding-form test
If test is true, evaluates then with binding-form bound to the value of
test, if not, yields else"
{:added "1.0"}
([bindings then]
`(if-let ~bindings ~then nil))
([bindings then else & oldform]
(assert-args
(vector? bindings) "a vector for its binding"
(nil? oldform) "1 or 2 forms after binding vector"
(= 2 (count bindings)) "exactly 2 forms in binding vector")
(let [form (bindings 0) tst (bindings 1)]
`(let [temp# ~tst]
(if temp#
(let [~form temp#]
~then)
~else)))))
(defmacro when-let
"bindings => binding-form test
When test is true, evaluates body with binding-form bound to the value of test"
{:added "1.0"}
[bindings & body]
(assert-args
(vector? bindings) "a vector for its binding"
(= 2 (count bindings)) "exactly 2 forms in binding vector")
(let [form (bindings 0) tst (bindings 1)]
`(let [temp# ~tst]
(when temp#
(let [~form temp#]
~@body)))))
(defmacro if-some
"bindings => binding-form test
If test is not nil, evaluates then with binding-form bound to the
value of test, if not, yields else"
{:added "1.6"}
([bindings then]
`(if-some ~bindings ~then nil))
([bindings then else & oldform]
(assert-args
(vector? bindings) "a vector for its binding"
(nil? oldform) "1 or 2 forms after binding vector"
(= 2 (count bindings)) "exactly 2 forms in binding vector")
(let [form (bindings 0) tst (bindings 1)]
`(let [temp# ~tst]
(if (nil? temp#)
~else
(let [~form temp#]
~then))))))
(defmacro when-some
"bindings => binding-form test
When test is not nil, evaluates body with binding-form bound to the
value of test"
{:added "1.6"}
[bindings & body]
(assert-args
(vector? bindings) "a vector for its binding"
(= 2 (count bindings)) "exactly 2 forms in binding vector")
(let [form (bindings 0) tst (bindings 1)]
`(let [temp# ~tst]
(if (nil? temp#)
nil
(let [~form temp#]
~@body)))))
(defn push-thread-bindings
"WARNING: This is a low-level function. Prefer high-level macros like
binding where ever possible.
Takes a map of Var/value pairs. Binds each Var to the associated value for
the current thread. Each call *MUST* be accompanied by a matching call to
pop-thread-bindings wrapped in a try-finally!
(push-thread-bindings bindings)
(try
...
(finally
(pop-thread-bindings)))"
{:added "1.1"
:static true}
[bindings]
(clojure.lang.Var/pushThreadBindings bindings))
(defn pop-thread-bindings
"Pop one set of bindings pushed with push-binding before. It is an error to
pop bindings without pushing before."
{:added "1.1"
:static true}
[]
(clojure.lang.Var/popThreadBindings))
(defn get-thread-bindings
"Get a map with the Var/value pairs which is currently in effect for the
current thread."
{:added "1.1"
:static true}
[]
(clojure.lang.Var/getThreadBindings))
(defmacro binding
"binding => var-symbol init-expr
Creates new bindings for the (already-existing) vars, with the
supplied initial values, executes the exprs in an implicit do, then
re-establishes the bindings that existed before. The new bindings
are made in parallel (unlike let); all init-exprs are evaluated
before the vars are bound to their new values."
{:added "1.0"}
[bindings & body]
(assert-args
(vector? bindings) "a vector for its binding"
(even? (count bindings)) "an even number of forms in binding vector")
(let [var-ize (fn [var-vals]
(loop [ret [] vvs (seq var-vals)]
(if vvs
(recur (conj (conj ret `(var ~(first vvs))) (second vvs))
(next (next vvs)))
(seq ret))))]
`(let []
(push-thread-bindings (hash-map ~@(var-ize bindings)))
(try
~@body
(finally
(pop-thread-bindings))))))
(defn with-bindings*
"Takes a map of Var/value pairs. Installs for the given Vars the associated
values as thread-local bindings. Then calls f with the supplied arguments.
Pops the installed bindings after f returned. Returns whatever f returns."
{:added "1.1"
:static true}
[binding-map f & args]
(push-thread-bindings binding-map)
(try
(apply f args)
(finally
(pop-thread-bindings))))
(defmacro with-bindings
"Takes a map of Var/value pairs. Installs for the given Vars the associated
values as thread-local bindings. The executes body. Pops the installed
bindings after body was evaluated. Returns the value of body."
{:added "1.1"}
[binding-map & body]
`(with-bindings* ~binding-map (fn [] ~@body)))
(defn bound-fn*
"Returns a function, which will install the same bindings in effect as in
the thread at the time bound-fn* was called and then call f with any given
arguments. This may be used to define a helper function which runs on a
different thread, but needs the same bindings in place."
{:added "1.1"
:static true}
[f]
(let [bindings (get-thread-bindings)]
(fn [& args]
(apply with-bindings* bindings f args))))
(defmacro bound-fn
"Returns a function defined by the given fntail, which will install the
same bindings in effect as in the thread at the time bound-fn was called.
This may be used to define a helper function which runs on a different
thread, but needs the same bindings in place."
{:added "1.1"}
[& fntail]
`(bound-fn* (fn ~@fntail)))
(defn find-var
"Returns the global var named by the namespace-qualified symbol, or
nil if no var with that name."
{:added "1.0"
:static true}
[sym] (. clojure.lang.Var (find sym)))
(defn binding-conveyor-fn
{:private true
:added "1.3"}
[f]
(let [frame (clojure.lang.Var/cloneThreadBindingFrame)]
(fn
([]
(clojure.lang.Var/resetThreadBindingFrame frame)
(f))
([x]
(clojure.lang.Var/resetThreadBindingFrame frame)
(f x))
([x y]
(clojure.lang.Var/resetThreadBindingFrame frame)
(f x y))
([x y z]
(clojure.lang.Var/resetThreadBindingFrame frame)
(f x y z))
([x y z & args]
(clojure.lang.Var/resetThreadBindingFrame frame)
(apply f x y z args)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Refs ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn ^{:private true}
setup-reference [^clojure.lang.ARef r options]
(let [opts (apply hash-map options)]
(when (:meta opts)
(.resetMeta r (:meta opts)))
(when (:validator opts)
(.setValidator r (:validator opts)))
r))
(defn agent
"Creates and returns an agent with an initial value of state and
zero or more options (in any order):
:meta metadata-map
:validator validate-fn
:error-handler handler-fn
:error-mode mode-keyword
If metadata-map is supplied, it will become the metadata on the
agent. validate-fn must be nil or a side-effect-free fn of one
argument, which will be passed the intended new state on any state
change. If the new state is unacceptable, the validate-fn should
return false or throw an exception. handler-fn is called if an
action throws an exception or if validate-fn rejects a new state --
see set-error-handler! for details. The mode-keyword may be either
:continue (the default if an error-handler is given) or :fail (the
default if no error-handler is given) -- see set-error-mode! for
details."
{:added "1.0"
:static true
}
([state & options]
(let [a (new clojure.lang.Agent state)
opts (apply hash-map options)]
(setup-reference a options)
(when (:error-handler opts)
(.setErrorHandler a (:error-handler opts)))
(.setErrorMode a (or (:error-mode opts)
(if (:error-handler opts) :continue :fail)))
a)))
(defn set-agent-send-executor!
"Sets the ExecutorService to be used by send"
{:added "1.5"}
[executor]
(set! clojure.lang.Agent/pooledExecutor executor))
(defn set-agent-send-off-executor!
"Sets the ExecutorService to be used by send-off"
{:added "1.5"}
[executor]
(set! clojure.lang.Agent/soloExecutor executor))
(defn send-via
"Dispatch an action to an agent. Returns the agent immediately.
Subsequently, in a thread supplied by executor, the state of the agent
will be set to the value of:
(apply action-fn state-of-agent args)"
{:added "1.5"}
[executor ^clojure.lang.Agent a f & args]
(.dispatch a (binding [*agent* a] (binding-conveyor-fn f)) args executor))
(defn send
"Dispatch an action to an agent. Returns the agent immediately.
Subsequently, in a thread from a thread pool, the state of the agent
will be set to the value of:
(apply action-fn state-of-agent args)"
{:added "1.0"
:static true}
[^clojure.lang.Agent a f & args]
(apply send-via clojure.lang.Agent/pooledExecutor a f args))
(defn send-off
"Dispatch a potentially blocking action to an agent. Returns the
agent immediately. Subsequently, in a separate thread, the state of
the agent will be set to the value of:
(apply action-fn state-of-agent args)"
{:added "1.0"
:static true}
[^clojure.lang.Agent a f & args]
(apply send-via clojure.lang.Agent/soloExecutor a f args))
(defn release-pending-sends
"Normally, actions sent directly or indirectly during another action
are held until the action completes (changes the agent's
state). This function can be used to dispatch any pending sent
actions immediately. This has no impact on actions sent during a
transaction, which are still held until commit. If no action is
occurring, does nothing. Returns the number of actions dispatched."
{:added "1.0"
:static true}
[] (clojure.lang.Agent/releasePendingSends))
(defn add-watch
"Adds a watch function to an agent/atom/var/ref reference. The watch
fn must be a fn of 4 args: a key, the reference, its old-state, its
new-state. Whenever the reference's state might have been changed,
any registered watches will have their functions called. The watch fn
will be called synchronously, on the agent's thread if an agent,
before any pending sends if agent or ref. Note that an atom's or
ref's state may have changed again prior to the fn call, so use
old/new-state rather than derefing the reference. Note also that watch
fns may be called from multiple threads simultaneously. Var watchers
are triggered only by root binding changes, not thread-local
set!s. Keys must be unique per reference, and can be used to remove
the watch with remove-watch, but are otherwise considered opaque by
the watch mechanism."
{:added "1.0"
:static true}
[^clojure.lang.IRef reference key fn] (.addWatch reference key fn))
(defn remove-watch
"Removes a watch (set by add-watch) from a reference"
{:added "1.0"
:static true}
[^clojure.lang.IRef reference key]
(.removeWatch reference key))
(defn agent-error
"Returns the exception thrown during an asynchronous action of the
agent if the agent is failed. Returns nil if the agent is not
failed."
{:added "1.2"
:static true}
[^clojure.lang.Agent a] (.getError a))
(defn restart-agent
"When an agent is failed, changes the agent state to new-state and
then un-fails the agent so that sends are allowed again. If
a :clear-actions true option is given, any actions queued on the
agent that were being held while it was failed will be discarded,
otherwise those held actions will proceed. The new-state must pass
the validator if any, or restart will throw an exception and the
agent will remain failed with its old state and error. Watchers, if
any, will NOT be notified of the new state. Throws an exception if
the agent is not failed."
{:added "1.2"
:static true
}
[^clojure.lang.Agent a, new-state & options]
(let [opts (apply hash-map options)]
(.restart a new-state (if (:clear-actions opts) true false))))
(defn set-error-handler!
"Sets the error-handler of agent a to handler-fn. If an action
being run by the agent throws an exception or doesn't pass the
validator fn, handler-fn will be called with two arguments: the
agent and the exception."
{:added "1.2"
:static true}
[^clojure.lang.Agent a, handler-fn]
(.setErrorHandler a handler-fn))
(defn error-handler
"Returns the error-handler of agent a, or nil if there is none.
See set-error-handler!"
{:added "1.2"
:static true}
[^clojure.lang.Agent a]
(.getErrorHandler a))
(defn set-error-mode!
"Sets the error-mode of agent a to mode-keyword, which must be
either :fail or :continue. If an action being run by the agent
throws an exception or doesn't pass the validator fn, an
error-handler may be called (see set-error-handler!), after which,
if the mode is :continue, the agent will continue as if neither the
action that caused the error nor the error itself ever happened.
If the mode is :fail, the agent will become failed and will stop
accepting new 'send' and 'send-off' actions, and any previously
queued actions will be held until a 'restart-agent'. Deref will
still work, returning the state of the agent before the error."
{:added "1.2"
:static true}
[^clojure.lang.Agent a, mode-keyword]
(.setErrorMode a mode-keyword))
(defn error-mode
"Returns the error-mode of agent a. See set-error-mode!"
{:added "1.2"
:static true}
[^clojure.lang.Agent a]
(.getErrorMode a))
(defn agent-errors
"DEPRECATED: Use 'agent-error' instead.
Returns a sequence of the exceptions thrown during asynchronous
actions of the agent."
{:added "1.0"
:deprecated "1.2"}
[a]
(when-let [e (agent-error a)]
(list e)))
(defn clear-agent-errors
"DEPRECATED: Use 'restart-agent' instead.
Clears any exceptions thrown during asynchronous actions of the
agent, allowing subsequent actions to occur."
{:added "1.0"
:deprecated "1.2"}
[^clojure.lang.Agent a] (restart-agent a (.deref a)))
(defn shutdown-agents
"Initiates a shutdown of the thread pools that back the agent
system. Running actions will complete, but no new actions will be
accepted"
{:added "1.0"
:static true}
[] (. clojure.lang.Agent shutdown))
(defn ref
"Creates and returns a Ref with an initial value of x and zero or
more options (in any order):
:meta metadata-map
:validator validate-fn
:min-history (default 0)
:max-history (default 10)
If metadata-map is supplied, it will become the metadata on the
ref. validate-fn must be nil or a side-effect-free fn of one
argument, which will be passed the intended new state on any state
change. If the new state is unacceptable, the validate-fn should
return false or throw an exception. validate-fn will be called on
transaction commit, when all refs have their final values.
Normally refs accumulate history dynamically as needed to deal with
read demands. If you know in advance you will need history you can
set :min-history to ensure it will be available when first needed (instead
of after a read fault). History is limited, and the limit can be set
with :max-history."
{:added "1.0"
:static true
}
([x] (new clojure.lang.Ref x))
([x & options]
(let [r ^clojure.lang.Ref (setup-reference (ref x) options)
opts (apply hash-map options)]
(when (:max-history opts)
(.setMaxHistory r (:max-history opts)))
(when (:min-history opts)
(.setMinHistory r (:min-history opts)))
r)))
(defn ^:private deref-future
([^java.util.concurrent.Future fut]
(.get fut))
([^java.util.concurrent.Future fut timeout-ms timeout-val]
(try (.get fut timeout-ms java.util.concurrent.TimeUnit/MILLISECONDS)
(catch java.util.concurrent.TimeoutException e
timeout-val))))
(defn deref
"Also reader macro: @ref/@agent/@var/@atom/@delay/@future/@promise. Within a transaction,
returns the in-transaction-value of ref, else returns the
most-recently-committed value of ref. When applied to a var, agent
or atom, returns its current state. When applied to a delay, forces
it if not already forced. When applied to a future, will block if
computation not complete. When applied to a promise, will block
until a value is delivered. The variant taking a timeout can be
used for blocking references (futures and promises), and will return
timeout-val if the timeout (in milliseconds) is reached before a
value is available. See also - realized?."
{:added "1.0"
:static true}
([ref] (if (instance? clojure.lang.IDeref ref)
(.deref ^clojure.lang.IDeref ref)
(deref-future ref)))
([ref timeout-ms timeout-val]
(if (instance? clojure.lang.IBlockingDeref ref)
(.deref ^clojure.lang.IBlockingDeref ref timeout-ms timeout-val)
(deref-future ref timeout-ms timeout-val))))
(defn atom
"Creates and returns an Atom with an initial value of x and zero or
more options (in any order):
:meta metadata-map
:validator validate-fn
If metadata-map is supplied, it will become the metadata on the
atom. validate-fn must be nil or a side-effect-free fn of one
argument, which will be passed the intended new state on any state
change. If the new state is unacceptable, the validate-fn should
return false or throw an exception."
{:added "1.0"
:static true}
([x] (new clojure.lang.Atom x))
([x & options] (setup-reference (atom x) options)))
(defn swap!
"Atomically swaps the value of atom to be:
(apply f current-value-of-atom args). Note that f may be called
multiple times, and thus should be free of side effects. Returns
the value that was swapped in."
{:added "1.0"
:static true}
([^clojure.lang.IAtom atom f] (.swap atom f))
([^clojure.lang.IAtom atom f x] (.swap atom f x))
([^clojure.lang.IAtom atom f x y] (.swap atom f x y))
([^clojure.lang.IAtom atom f x y & args] (.swap atom f x y args)))
(defn compare-and-set!
"Atomically sets the value of atom to newval if and only if the
current value of the atom is identical to oldval. Returns true if
set happened, else false"
{:added "1.0"
:static true}
[^clojure.lang.IAtom atom oldval newval] (.compareAndSet atom oldval newval))
(defn reset!
"Sets the value of atom to newval without regard for the
current value. Returns newval."
{:added "1.0"
:static true}
[^clojure.lang.IAtom atom newval] (.reset atom newval))
(defn set-validator!
"Sets the validator-fn for a var/ref/agent/atom. validator-fn must be nil or a
side-effect-free fn of one argument, which will be passed the intended
new state on any state change. If the new state is unacceptable, the
validator-fn should return false or throw an exception. If the current state (root
value if var) is not acceptable to the new validator, an exception
will be thrown and the validator will not be changed."
{:added "1.0"
:static true}
[^clojure.lang.IRef iref validator-fn] (. iref (setValidator validator-fn)))
(defn get-validator
"Gets the validator-fn for a var/ref/agent/atom."
{:added "1.0"
:static true}
[^clojure.lang.IRef iref] (. iref (getValidator)))
(defn alter-meta!
"Atomically sets the metadata for a namespace/var/ref/agent/atom to be:
(apply f its-current-meta args)
f must be free of side-effects"
{:added "1.0"
:static true}
[^clojure.lang.IReference iref f & args] (.alterMeta iref f args))
(defn reset-meta!
"Atomically resets the metadata for a namespace/var/ref/agent/atom"
{:added "1.0"
:static true}
[^clojure.lang.IReference iref metadata-map] (.resetMeta iref metadata-map))
(defn commute
"Must be called in a transaction. Sets the in-transaction-value of
ref to:
(apply fun in-transaction-value-of-ref args)
and returns the in-transaction-value of ref.
At the commit point of the transaction, sets the value of ref to be:
(apply fun most-recently-committed-value-of-ref args)
Thus fun should be commutative, or, failing that, you must accept
last-one-in-wins behavior. commute allows for more concurrency than
ref-set."
{:added "1.0"
:static true}
[^clojure.lang.Ref ref fun & args]
(. ref (commute fun args)))
(defn alter
"Must be called in a transaction. Sets the in-transaction-value of
ref to:
(apply fun in-transaction-value-of-ref args)
and returns the in-transaction-value of ref."
{:added "1.0"
:static true}
[^clojure.lang.Ref ref fun & args]
(. ref (alter fun args)))
(defn ref-set
"Must be called in a transaction. Sets the value of ref.
Returns val."
{:added "1.0"
:static true}
[^clojure.lang.Ref ref val]
(. ref (set val)))
(defn ref-history-count
"Returns the history count of a ref"
{:added "1.1"
:static true}
[^clojure.lang.Ref ref]
(.getHistoryCount ref))
(defn ref-min-history
"Gets the min-history of a ref, or sets it and returns the ref"
{:added "1.1"
:static true}
([^clojure.lang.Ref ref]
(.getMinHistory ref))
([^clojure.lang.Ref ref n]
(.setMinHistory ref n)))
(defn ref-max-history
"Gets the max-history of a ref, or sets it and returns the ref"
{:added "1.1"
:static true}
([^clojure.lang.Ref ref]
(.getMaxHistory ref))
([^clojure.lang.Ref ref n]
(.setMaxHistory ref n)))
(defn ensure
"Must be called in a transaction. Protects the ref from modification
by other transactions. Returns the in-transaction-value of
ref. Allows for more concurrency than (ref-set ref @ref)"
{:added "1.0"
:static true}
[^clojure.lang.Ref ref]
(. ref (touch))
(. ref (deref)))
(defmacro sync
"transaction-flags => TBD, pass nil for now
Runs the exprs (in an implicit do) in a transaction that encompasses
exprs and any nested calls. Starts a transaction if none is already
running on this thread. Any uncaught exception will abort the
transaction and flow out of sync. The exprs may be run more than
once, but any effects on Refs will be atomic."
{:added "1.0"}
[flags-ignored-for-now & body]
`(. clojure.lang.LockingTransaction
(runInTransaction (fn [] ~@body))))
(defmacro io!
"If an io! block occurs in a transaction, throws an
IllegalStateException, else runs body in an implicit do. If the
first expression in body is a literal string, will use that as the
exception message."
{:added "1.0"}
[& body]
(let [message (when (string? (first body)) (first body))
body (if message (next body) body)]
`(if (clojure.lang.LockingTransaction/isRunning)
(throw (new IllegalStateException ~(or message "I/O in transaction")))
(do ~@body))))
(defn volatile!
"Creates and returns a Volatile with an initial value of val."
{:added "1.7"
:tag clojure.lang.Volatile}
[val]
(clojure.lang.Volatile. val))
(defn vreset!
"Sets the value of volatile to newval without regard for the
current value. Returns newval."
{:added "1.7"}
[^clojure.lang.Volatile vol newval]
(.reset vol newval))
(defmacro vswap!
"Non-atomically swaps the value of the volatile as if:
(apply f current-value-of-vol args). Returns the value that
was swapped in."
{:added "1.7"}
[vol f & args]
(let [v (with-meta vol {:tag 'clojure.lang.Volatile})]
`(.reset ~v (~f (.deref ~v) ~@args))))
(defn volatile?
"Returns true if x is a volatile."
{:added "1.7"}
[x]
(instance? clojure.lang.Volatile x))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; fn stuff ;;;;;;;;;;;;;;;;
(defn comp
"Takes a set of functions and returns a fn that is the composition
of those fns. The returned fn takes a variable number of args,
applies the rightmost of fns to the args, the next
fn (right-to-left) to the result, etc."
{:added "1.0"
:static true}
([] identity)
([f] f)
([f g]
(fn
([] (f (g)))
([x] (f (g x)))
([x y] (f (g x y)))
([x y z] (f (g x y z)))
([x y z & args] (f (apply g x y z args)))))
([f g & fs]
(reduce1 comp (list* f g fs))))
(defn juxt
"Takes a set of functions and returns a fn that is the juxtaposition
of those fns. The returned fn takes a variable number of args, and
returns a vector containing the result of applying each fn to the
args (left-to-right).
((juxt a b c) x) => [(a x) (b x) (c x)]"
{:added "1.1"
:static true}
([f]
(fn
([] [(f)])
([x] [(f x)])
([x y] [(f x y)])
([x y z] [(f x y z)])
([x y z & args] [(apply f x y z args)])))
([f g]
(fn
([] [(f) (g)])
([x] [(f x) (g x)])
([x y] [(f x y) (g x y)])
([x y z] [(f x y z) (g x y z)])
([x y z & args] [(apply f x y z args) (apply g x y z args)])))
([f g h]
(fn
([] [(f) (g) (h)])
([x] [(f x) (g x) (h x)])
([x y] [(f x y) (g x y) (h x y)])
([x y z] [(f x y z) (g x y z) (h x y z)])
([x y z & args] [(apply f x y z args) (apply g x y z args) (apply h x y z args)])))
([f g h & fs]
(let [fs (list* f g h fs)]
(fn
([] (reduce1 #(conj %1 (%2)) [] fs))
([x] (reduce1 #(conj %1 (%2 x)) [] fs))
([x y] (reduce1 #(conj %1 (%2 x y)) [] fs))
([x y z] (reduce1 #(conj %1 (%2 x y z)) [] fs))
([x y z & args] (reduce1 #(conj %1 (apply %2 x y z args)) [] fs))))))
(defn partial
"Takes a function f and fewer than the normal arguments to f, and
returns a fn that takes a variable number of additional args. When
called, the returned function calls f with args + additional args."
{:added "1.0"
:static true}
([f] f)
([f arg1]
(fn
([] (f arg1))
([x] (f arg1 x))
([x y] (f arg1 x y))
([x y z] (f arg1 x y z))
([x y z & args] (apply f arg1 x y z args))))
([f arg1 arg2]
(fn
([] (f arg1 arg2))
([x] (f arg1 arg2 x))
([x y] (f arg1 arg2 x y))
([x y z] (f arg1 arg2 x y z))
([x y z & args] (apply f arg1 arg2 x y z args))))
([f arg1 arg2 arg3]
(fn
([] (f arg1 arg2 arg3))
([x] (f arg1 arg2 arg3 x))
([x y] (f arg1 arg2 arg3 x y))
([x y z] (f arg1 arg2 arg3 x y z))
([x y z & args] (apply f arg1 arg2 arg3 x y z args))))
([f arg1 arg2 arg3 & more]
(fn [& args] (apply f arg1 arg2 arg3 (concat more args)))))
;;;;;;;;;;;;;;;;;;; sequence fns ;;;;;;;;;;;;;;;;;;;;;;;
(defn sequence
"Coerces coll to a (possibly empty) sequence, if it is not already
one. Will not force a lazy seq. (sequence nil) yields (), When a
transducer is supplied, returns a lazy sequence of applications of
the transform to the items in coll(s), i.e. to the set of first
items of each coll, followed by the set of second
items in each coll, until any one of the colls is exhausted. Any
remaining items in other colls are ignored. The transform should accept
number-of-colls arguments"
{:added "1.0"
:static true}
([coll]
(if (seq? coll) coll
(or (seq coll) ())))
([xform coll]
(or (clojure.lang.RT/chunkIteratorSeq
(clojure.lang.TransformerIterator/create xform (clojure.lang.RT/iter coll)))
()))
([xform coll & colls]
(or (clojure.lang.RT/chunkIteratorSeq
(clojure.lang.TransformerIterator/createMulti
xform
(map #(clojure.lang.RT/iter %) (cons coll colls))))
())))
(defn every?
"Returns true if (pred x) is logical true for every x in coll, else
false."
{:tag Boolean
:added "1.0"
:static true}
[pred coll]
(cond
(nil? (seq coll)) true
(pred (first coll)) (recur pred (next coll))
:else false))
(def
^{:tag Boolean
:doc "Returns false if (pred x) is logical true for every x in
coll, else true."
:arglists '([pred coll])
:added "1.0"}
not-every? (comp not every?))
(defn some
"Returns the first logical true value of (pred x) for any x in coll,
else nil. One common idiom is to use a set as pred, for example
this will return :fred if :fred is in the sequence, otherwise nil:
(some #{:fred} coll)"
{:added "1.0"
:static true}
[pred coll]
(when (seq coll)
(or (pred (first coll)) (recur pred (next coll)))))
(def
^{:tag Boolean
:doc "Returns false if (pred x) is logical true for any x in coll,
else true."
:arglists '([pred coll])
:added "1.0"}
not-any? (comp not some))
;will be redefed later with arg checks
(defmacro dotimes
"bindings => name n
Repeatedly executes body (presumably for side-effects) with name
bound to integers from 0 through n-1."
{:added "1.0"}
[bindings & body]
(let [i (first bindings)
n (second bindings)]
`(let [n# (clojure.lang.RT/longCast ~n)]
(loop [~i 0]
(when (< ~i n#)
~@body
(recur (unchecked-inc ~i)))))))
(defn map
"Returns a lazy sequence consisting of the result of applying f to
the set of first items of each coll, followed by applying f to the
set of second items in each coll, until any one of the colls is
exhausted. Any remaining items in other colls are ignored. Function
f should accept number-of-colls arguments. Returns a transducer when
no collection is provided."
{:added "1.0"
:static true}
([f]
(fn [rf]
(fn
([] (rf))
([result] (rf result))
([result input]
(rf result (f input)))
([result input & inputs]
(rf result (apply f input inputs))))))
([f coll]
(lazy-seq
(when-let [s (seq coll)]
(if (chunked-seq? s)
(let [c (chunk-first s)
size (int (count c))
b (chunk-buffer size)]
(dotimes [i size]
(chunk-append b (f (.nth c i))))
(chunk-cons (chunk b) (map f (chunk-rest s))))
(cons (f (first s)) (map f (rest s)))))))
([f c1 c2]
(lazy-seq
(let [s1 (seq c1) s2 (seq c2)]
(when (and s1 s2)
(cons (f (first s1) (first s2))
(map f (rest s1) (rest s2)))))))
([f c1 c2 c3]
(lazy-seq
(let [s1 (seq c1) s2 (seq c2) s3 (seq c3)]
(when (and s1 s2 s3)
(cons (f (first s1) (first s2) (first s3))
(map f (rest s1) (rest s2) (rest s3)))))))
([f c1 c2 c3 & colls]
(let [step (fn step [cs]
(lazy-seq
(let [ss (map seq cs)]
(when (every? identity ss)
(cons (map first ss) (step (map rest ss)))))))]
(map #(apply f %) (step (conj colls c3 c2 c1))))))
(defmacro declare
"defs the supplied var names with no bindings, useful for making forward declarations."
{:added "1.0"}
[& names] `(do ~@(map #(list 'def (vary-meta % assoc :declared true)) names)))
(declare cat)
(defn mapcat
"Returns the result of applying concat to the result of applying map
to f and colls. Thus function f should return a collection. Returns
a transducer when no collections are provided"
{:added "1.0"
:static true}
([f] (comp (map f) cat))
([f & colls]
(apply concat (apply map f colls))))
(defn filter
"Returns a lazy sequence of the items in coll for which
(pred item) returns true. pred must be free of side-effects.
Returns a transducer when no collection is provided."
{:added "1.0"
:static true}
([pred]
(fn [rf]
(fn
([] (rf))
([result] (rf result))
([result input]
(if (pred input)
(rf result input)
result)))))
([pred coll]
(lazy-seq
(when-let [s (seq coll)]
(if (chunked-seq? s)
(let [c (chunk-first s)
size (count c)
b (chunk-buffer size)]
(dotimes [i size]
(let [v (.nth c i)]
(when (pred v)
(chunk-append b v))))
(chunk-cons (chunk b) (filter pred (chunk-rest s))))
(let [f (first s) r (rest s)]
(if (pred f)
(cons f (filter pred r))
(filter pred r))))))))
(defn remove
"Returns a lazy sequence of the items in coll for which
(pred item) returns false. pred must be free of side-effects.
Returns a transducer when no collection is provided."
{:added "1.0"
:static true}
([pred] (filter (complement pred)))
([pred coll]
(filter (complement pred) coll)))
(defn reduced
"Wraps x in a way such that a reduce will terminate with the value x"
{:added "1.5"}
[x]
(clojure.lang.Reduced. x))
(defn reduced?
"Returns true if x is the result of a call to reduced"
{:inline (fn [x] `(clojure.lang.RT/isReduced ~x ))
:inline-arities #{1}
:added "1.5"}
([x] (clojure.lang.RT/isReduced x)))
(defn ensure-reduced
"If x is already reduced?, returns it, else returns (reduced x)"
{:added "1.7"}
[x]
(if (reduced? x) x (reduced x)))
(defn unreduced
"If x is reduced?, returns (deref x), else returns x"
{:added "1.7"}
[x]
(if (reduced? x) (deref x) x))
(defn take
"Returns a lazy sequence of the first n items in coll, or all items if
there are fewer than n. Returns a stateful transducer when
no collection is provided."
{:added "1.0"
:static true}
([n]
(fn [rf]
(let [nv (volatile! n)]
(fn
([] (rf))
([result] (rf result))
([result input]
(let [n @nv
nn (vswap! nv dec)
result (if (pos? n)
(rf result input)
result)]
(if (not (pos? nn))
(ensure-reduced result)
result)))))))
([n coll]
(lazy-seq
(when (pos? n)
(when-let [s (seq coll)]
(cons (first s) (take (dec n) (rest s))))))))
(defn take-while
"Returns a lazy sequence of successive items from coll while
(pred item) returns true. pred must be free of side-effects.
Returns a transducer when no collection is provided."
{:added "1.0"
:static true}
([pred]
(fn [rf]
(fn
([] (rf))
([result] (rf result))
([result input]
(if (pred input)
(rf result input)
(reduced result))))))
([pred coll]
(lazy-seq
(when-let [s (seq coll)]
(when (pred (first s))
(cons (first s) (take-while pred (rest s))))))))
(defn drop
"Returns a lazy sequence of all but the first n items in coll.
Returns a stateful transducer when no collection is provided."
{:added "1.0"
:static true}
([n]
(fn [rf]
(let [nv (volatile! n)]
(fn
([] (rf))
([result] (rf result))
([result input]
(let [n @nv]
(vswap! nv dec)
(if (pos? n)
result
(rf result input))))))))
([n coll]
(let [step (fn [n coll]
(let [s (seq coll)]
(if (and (pos? n) s)
(recur (dec n) (rest s))
s)))]
(lazy-seq (step n coll)))))
(defn drop-last
"Return a lazy sequence of all but the last n (default 1) items in coll"
{:added "1.0"
:static true}
([s] (drop-last 1 s))
([n s] (map (fn [x _] x) s (drop n s))))
(defn take-last
"Returns a seq of the last n items in coll. Depending on the type
of coll may be no better than linear time. For vectors, see also subvec."
{:added "1.1"
:static true}
[n coll]
(loop [s (seq coll), lead (seq (drop n coll))]
(if lead
(recur (next s) (next lead))
s)))
(defn drop-while
"Returns a lazy sequence of the items in coll starting from the
first item for which (pred item) returns logical false. Returns a
stateful transducer when no collection is provided."
{:added "1.0"
:static true}
([pred]
(fn [rf]
(let [dv (volatile! true)]
(fn
([] (rf))
([result] (rf result))
([result input]
(let [drop? @dv]
(if (and drop? (pred input))
result
(do
(vreset! dv nil)
(rf result input)))))))))
([pred coll]
(let [step (fn [pred coll]
(let [s (seq coll)]
(if (and s (pred (first s)))
(recur pred (rest s))
s)))]
(lazy-seq (step pred coll)))))
(defn cycle
"Returns a lazy (infinite!) sequence of repetitions of the items in coll."
{:added "1.0"
:static true}
[coll] (clojure.lang.Cycle/create (seq coll)))
(defn split-at
"Returns a vector of [(take n coll) (drop n coll)]"
{:added "1.0"
:static true}
[n coll]
[(take n coll) (drop n coll)])
(defn split-with
"Returns a vector of [(take-while pred coll) (drop-while pred coll)]"
{:added "1.0"
:static true}
[pred coll]
[(take-while pred coll) (drop-while pred coll)])
(defn repeat
"Returns a lazy (infinite!, or length n if supplied) sequence of xs."
{:added "1.0"
:static true}
([x] (clojure.lang.Repeat/create x))
([n x] (clojure.lang.Repeat/create n x)))
(defn replicate
"DEPRECATED: Use 'repeat' instead.
Returns a lazy seq of n xs."
{:added "1.0"
:deprecated "1.3"}
[n x] (take n (repeat x)))
(defn iterate
"Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects"
{:added "1.0"
:static true}
[f x] (clojure.lang.Iterate/create f x) )
(defn range
"Returns a lazy seq of nums from start (inclusive) to end
(exclusive), by step, where start defaults to 0, step to 1, and end to
infinity. When step is equal to 0, returns an infinite sequence of
start. When start is equal to end, returns empty list."
{:added "1.0"
:static true}
([]
(iterate inc' 0))
([end]
(if (instance? Long end)
(clojure.lang.LongRange/create end)
(clojure.lang.Range/create end)))
([start end]
(if (and (instance? Long start) (instance? Long end))
(clojure.lang.LongRange/create start end)
(clojure.lang.Range/create start end)))
([start end step]
(if (and (instance? Long start) (instance? Long end) (instance? Long step))
(clojure.lang.LongRange/create start end step)
(clojure.lang.Range/create start end step))))
(defn merge
"Returns a map that consists of the rest of the maps conj-ed onto
the first. If a key occurs in more than one map, the mapping from
the latter (left-to-right) will be the mapping in the result."
{:added "1.0"
:static true}
[& maps]
(when (some identity maps)
(reduce1 #(conj (or %1 {}) %2) maps)))
(defn merge-with
"Returns a map that consists of the rest of the maps conj-ed onto
the first. If a key occurs in more than one map, the mapping(s)
from the latter (left-to-right) will be combined with the mapping in
the result by calling (f val-in-result val-in-latter)."
{:added "1.0"
:static true}
[f & maps]
(when (some identity maps)
(let [merge-entry (fn [m e]
(let [k (key e) v (val e)]
(if (contains? m k)
(assoc m k (f (get m k) v))
(assoc m k v))))
merge2 (fn [m1 m2]
(reduce1 merge-entry (or m1 {}) (seq m2)))]
(reduce1 merge2 maps))))
(defn zipmap
"Returns a map with the keys mapped to the corresponding vals."
{:added "1.0"
:static true}
[keys vals]
(loop [map {}
ks (seq keys)
vs (seq vals)]
(if (and ks vs)
(recur (assoc map (first ks) (first vs))
(next ks)
(next vs))
map)))
(defn line-seq
"Returns the lines of text from rdr as a lazy sequence of strings.
rdr must implement java.io.BufferedReader."
{:added "1.0"
:static true}
[^java.io.BufferedReader rdr]
(when-let [line (.readLine rdr)]
(cons line (lazy-seq (line-seq rdr)))))
(defn comparator
"Returns an implementation of java.util.Comparator based upon pred."
{:added "1.0"
:static true}
[pred]
(fn [x y]
(cond (pred x y) -1 (pred y x) 1 :else 0)))
(defn sort
"Returns a sorted sequence of the items in coll. If no comparator is
supplied, uses compare. comparator must implement
java.util.Comparator. If coll is a Java array, it will be modified.
To avoid this, sort a copy of the array."
{:added "1.0"
:static true}
([coll]
(sort compare coll))
([^java.util.Comparator comp coll]
(if (seq coll)
(let [a (to-array coll)]
(. java.util.Arrays (sort a comp))
(seq a))
())))
(defn sort-by
"Returns a sorted sequence of the items in coll, where the sort
order is determined by comparing (keyfn item). If no comparator is
supplied, uses compare. comparator must implement
java.util.Comparator. If coll is a Java array, it will be modified.
To avoid this, sort a copy of the array."
{:added "1.0"
:static true}
([keyfn coll]
(sort-by keyfn compare coll))
([keyfn ^java.util.Comparator comp coll]
(sort (fn [x y] (. comp (compare (keyfn x) (keyfn y)))) coll)))
(defn dorun
"When lazy sequences are produced via functions that have side
effects, any effects other than those needed to produce the first
element in the seq do not occur until the seq is consumed. dorun can
be used to force any effects. Walks through the successive nexts of
the seq, does not retain the head and returns nil."
{:added "1.0"
:static true}
([coll]
(when-let [s (seq coll)]
(recur (next s))))
([n coll]
(when (and (seq coll) (pos? n))
(recur (dec n) (next coll)))))
(defn doall
"When lazy sequences are produced via functions that have side
effects, any effects other than those needed to produce the first
element in the seq do not occur until the seq is consumed. doall can
be used to force any effects. Walks through the successive nexts of
the seq, retains the head and returns it, thus causing the entire
seq to reside in memory at one time."
{:added "1.0"
:static true}
([coll]
(dorun coll)
coll)
([n coll]
(dorun n coll)
coll))
(defn nthnext
"Returns the nth next of coll, (seq coll) when n is 0."
{:added "1.0"
:static true}
[coll n]
(loop [n n xs (seq coll)]
(if (and xs (pos? n))
(recur (dec n) (next xs))
xs)))
(defn nthrest
"Returns the nth rest of coll, coll when n is 0."
{:added "1.3"
:static true}
[coll n]
(loop [n n xs coll]
(if-let [xs (and (pos? n) (seq xs))]
(recur (dec n) (rest xs))
xs)))
(defn partition
"Returns a lazy sequence of lists of n items each, at offsets step
apart. If step is not supplied, defaults to n, i.e. the partitions
do not overlap. If a pad collection is supplied, use its elements as
necessary to complete last partition upto n items. In case there are
not enough padding elements, return a partition with less than n items."
{:added "1.0"
:static true}
([n coll]
(partition n n coll))
([n step coll]
(lazy-seq
(when-let [s (seq coll)]
(let [p (doall (take n s))]
(when (= n (count p))
(cons p (partition n step (nthrest s step))))))))
([n step pad coll]
(lazy-seq
(when-let [s (seq coll)]
(let [p (doall (take n s))]
(if (= n (count p))
(cons p (partition n step pad (nthrest s step)))
(list (take n (concat p pad)))))))))
;; evaluation
(defn eval
"Evaluates the form data structure (not text!) and returns the result."
{:added "1.0"
:static true}
[form] (. clojure.lang.Compiler (eval form)))
(defmacro doseq
"Repeatedly executes body (presumably for side-effects) with
bindings and filtering as provided by \"for\". Does not retain
the head of the sequence. Returns nil."
{:added "1.0"}
[seq-exprs & body]
(assert-args
(vector? seq-exprs) "a vector for its binding"
(even? (count seq-exprs)) "an even number of forms in binding vector")
(let [step (fn step [recform exprs]
(if-not exprs
[true `(do ~@body)]
(let [k (first exprs)
v (second exprs)]
(if (keyword? k)
(let [steppair (step recform (nnext exprs))
needrec (steppair 0)
subform (steppair 1)]
(cond
(= k :let) [needrec `(let ~v ~subform)]
(= k :while) [false `(when ~v
~subform
~@(when needrec [recform]))]
(= k :when) [false `(if ~v
(do
~subform
~@(when needrec [recform]))
~recform)]))
(let [seq- (gensym "seq_")
chunk- (with-meta (gensym "chunk_")
{:tag 'clojure.lang.IChunk})
count- (gensym "count_")
i- (gensym "i_")
recform `(recur (next ~seq-) nil 0 0)
steppair (step recform (nnext exprs))
needrec (steppair 0)
subform (steppair 1)
recform-chunk
`(recur ~seq- ~chunk- ~count- (unchecked-inc ~i-))
steppair-chunk (step recform-chunk (nnext exprs))
subform-chunk (steppair-chunk 1)]
[true
`(loop [~seq- (seq ~v), ~chunk- nil,
~count- 0, ~i- 0]
(if (< ~i- ~count-)
(let [~k (.nth ~chunk- ~i-)]
~subform-chunk
~@(when needrec [recform-chunk]))
(when-let [~seq- (seq ~seq-)]
(if (chunked-seq? ~seq-)
(let [c# (chunk-first ~seq-)]
(recur (chunk-rest ~seq-) c#
(int (count c#)) (int 0)))
(let [~k (first ~seq-)]
~subform
~@(when needrec [recform]))))))])))))]
(nth (step nil (seq seq-exprs)) 1)))
(defn await
"Blocks the current thread (indefinitely!) until all actions
dispatched thus far, from this thread or agent, to the agent(s) have
occurred. Will block on failed agents. Will never return if
a failed agent is restarted with :clear-actions true."
{:added "1.0"
:static true}
[& agents]
(io! "await in transaction"
(when *agent*
(throw (new Exception "Can't await in agent action")))
(let [latch (new java.util.concurrent.CountDownLatch (count agents))
count-down (fn [agent] (. latch (countDown)) agent)]
(doseq [agent agents]
(send agent count-down))
(. latch (await)))))
(defn ^:static await1 [^clojure.lang.Agent a]
(when (pos? (.getQueueCount a))
(await a))
a)
(defn await-for
"Blocks the current thread until all actions dispatched thus
far (from this thread or agent) to the agents have occurred, or the
timeout (in milliseconds) has elapsed. Returns logical false if
returning due to timeout, logical true otherwise."
{:added "1.0"
:static true}
[timeout-ms & agents]
(io! "await-for in transaction"
(when *agent*
(throw (new Exception "Can't await in agent action")))
(let [latch (new java.util.concurrent.CountDownLatch (count agents))
count-down (fn [agent] (. latch (countDown)) agent)]
(doseq [agent agents]
(send agent count-down))
(. latch (await timeout-ms (. java.util.concurrent.TimeUnit MILLISECONDS))))))
(defmacro dotimes
"bindings => name n
Repeatedly executes body (presumably for side-effects) with name
bound to integers from 0 through n-1."
{:added "1.0"}
[bindings & body]
(assert-args
(vector? bindings) "a vector for its binding"
(= 2 (count bindings)) "exactly 2 forms in binding vector")
(let [i (first bindings)
n (second bindings)]
`(let [n# (long ~n)]
(loop [~i 0]
(when (< ~i n#)
~@body
(recur (unchecked-inc ~i)))))))
#_(defn into
"Returns a new coll consisting of to-coll with all of the items of
from-coll conjoined."
{:added "1.0"}
[to from]
(let [ret to items (seq from)]
(if items
(recur (conj ret (first items)) (next items))
ret)))
;;;;;;;;;;;;;;;;;;;;; editable collections ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn transient
"Returns a new, transient version of the collection, in constant time."
{:added "1.1"
:static true}
[^clojure.lang.IEditableCollection coll]
(.asTransient coll))
(defn persistent!
"Returns a new, persistent version of the transient collection, in
constant time. The transient collection cannot be used after this
call, any such use will throw an exception."
{:added "1.1"
:static true}
[^clojure.lang.ITransientCollection coll]
(.persistent coll))
(defn conj!
"Adds x to the transient collection, and return coll. The 'addition'
may happen at different 'places' depending on the concrete type."
{:added "1.1"
:static true}
([] (transient []))
([coll] coll)
([^clojure.lang.ITransientCollection coll x]
(.conj coll x)))
(defn assoc!
"When applied to a transient map, adds mapping of key(s) to
val(s). When applied to a transient vector, sets the val at index.
Note - index must be <= (count vector). Returns coll."
{:added "1.1"
:static true}
([^clojure.lang.ITransientAssociative coll key val] (.assoc coll key val))
([^clojure.lang.ITransientAssociative coll key val & kvs]
(let [ret (.assoc coll key val)]
(if kvs
(recur ret (first kvs) (second kvs) (nnext kvs))
ret))))
(defn dissoc!
"Returns a transient map that doesn't contain a mapping for key(s)."
{:added "1.1"
:static true}
([^clojure.lang.ITransientMap map key] (.without map key))
([^clojure.lang.ITransientMap map key & ks]
(let [ret (.without map key)]
(if ks
(recur ret (first ks) (next ks))
ret))))
(defn pop!
"Removes the last item from a transient vector. If
the collection is empty, throws an exception. Returns coll"
{:added "1.1"
:static true}
[^clojure.lang.ITransientVector coll]
(.pop coll))
(defn disj!
"disj[oin]. Returns a transient set of the same (hashed/sorted) type, that
does not contain key(s)."
{:added "1.1"
:static true}
([set] set)
([^clojure.lang.ITransientSet set key]
(. set (disjoin key)))
([^clojure.lang.ITransientSet set key & ks]
(let [ret (. set (disjoin key))]
(if ks
(recur ret (first ks) (next ks))
ret))))
;redef into with batch support
(defn ^:private into1
"Returns a new coll consisting of to-coll with all of the items of
from-coll conjoined."
{:added "1.0"
:static true}
[to from]
(if (instance? clojure.lang.IEditableCollection to)
(persistent! (reduce1 conj! (transient to) from))
(reduce1 conj to from)))
(defmacro import
"import-list => (package-symbol class-name-symbols*)
For each name in class-name-symbols, adds a mapping from name to the
class named by package.name to the current namespace. Use :import in the ns
macro in preference to calling this directly."
{:added "1.0"}
[& import-symbols-or-lists]
(let [specs (map #(if (and (seq? %) (= 'quote (first %))) (second %) %)
import-symbols-or-lists)]
`(do ~@(map #(list 'clojure.core/import* %)
(reduce1 (fn [v spec]
(if (symbol? spec)
(conj v (name spec))
(let [p (first spec) cs (rest spec)]
(into1 v (map #(str p "." %) cs)))))
[] specs)))))
(defn into-array
"Returns an array with components set to the values in aseq. The array's
component type is type if provided, or the type of the first value in
aseq if present, or Object. All values in aseq must be compatible with
the component type. Class objects for the primitive types can be obtained
using, e.g., Integer/TYPE."
{:added "1.0"
:static true}
([aseq]
(clojure.lang.RT/seqToTypedArray (seq aseq)))
([type aseq]
(clojure.lang.RT/seqToTypedArray type (seq aseq))))
(defn ^{:private true}
array [& items]
(into-array items))
(defn class
"Returns the Class of x"
{:added "1.0"
:static true}
^Class [^Object x] (if (nil? x) x (. x (getClass))))
(defn type
"Returns the :type metadata of x, or its Class if none"
{:added "1.0"
:static true}
[x]
(or (get (meta x) :type) (class x)))
(defn num
"Coerce to Number"
{:tag Number
:inline (fn [x] `(. clojure.lang.Numbers (num ~x)))
:added "1.0"}
[x] (. clojure.lang.Numbers (num x)))
(defn long
"Coerce to long"
{:inline (fn [x] `(. clojure.lang.RT (longCast ~x)))
:added "1.0"}
[^Number x] (clojure.lang.RT/longCast x))
(defn float
"Coerce to float"
{:inline (fn [x] `(. clojure.lang.RT (~(if *unchecked-math* 'uncheckedFloatCast 'floatCast) ~x)))
:added "1.0"}
[^Number x] (clojure.lang.RT/floatCast x))
(defn double
"Coerce to double"
{:inline (fn [x] `(. clojure.lang.RT (doubleCast ~x)))
:added "1.0"}
[^Number x] (clojure.lang.RT/doubleCast x))
(defn short
"Coerce to short"
{:inline (fn [x] `(. clojure.lang.RT (~(if *unchecked-math* 'uncheckedShortCast 'shortCast) ~x)))
:added "1.0"}
[^Number x] (clojure.lang.RT/shortCast x))
(defn byte
"Coerce to byte"
{:inline (fn [x] `(. clojure.lang.RT (~(if *unchecked-math* 'uncheckedByteCast 'byteCast) ~x)))
:added "1.0"}
[^Number x] (clojure.lang.RT/byteCast x))
(defn char
"Coerce to char"
{:inline (fn [x] `(. clojure.lang.RT (~(if *unchecked-math* 'uncheckedCharCast 'charCast) ~x)))
:added "1.1"}
[x] (. clojure.lang.RT (charCast x)))
(defn boolean
"Coerce to boolean"
{
:inline (fn [x] `(. clojure.lang.RT (booleanCast ~x)))
:added "1.0"}
[x] (clojure.lang.RT/booleanCast x))
(defn unchecked-byte
"Coerce to byte. Subject to rounding or truncation."
{:inline (fn [x] `(. clojure.lang.RT (uncheckedByteCast ~x)))
:added "1.3"}
[^Number x] (clojure.lang.RT/uncheckedByteCast x))
(defn unchecked-short
"Coerce to short. Subject to rounding or truncation."
{:inline (fn [x] `(. clojure.lang.RT (uncheckedShortCast ~x)))
:added "1.3"}
[^Number x] (clojure.lang.RT/uncheckedShortCast x))
(defn unchecked-char
"Coerce to char. Subject to rounding or truncation."
{:inline (fn [x] `(. clojure.lang.RT (uncheckedCharCast ~x)))
:added "1.3"}
[x] (. clojure.lang.RT (uncheckedCharCast x)))
(defn unchecked-int
"Coerce to int. Subject to rounding or truncation."
{:inline (fn [x] `(. clojure.lang.RT (uncheckedIntCast ~x)))
:added "1.3"}
[^Number x] (clojure.lang.RT/uncheckedIntCast x))
(defn unchecked-long
"Coerce to long. Subject to rounding or truncation."
{:inline (fn [x] `(. clojure.lang.RT (uncheckedLongCast ~x)))
:added "1.3"}
[^Number x] (clojure.lang.RT/uncheckedLongCast x))
(defn unchecked-float
"Coerce to float. Subject to rounding."
{:inline (fn [x] `(. clojure.lang.RT (uncheckedFloatCast ~x)))
:added "1.3"}
[^Number x] (clojure.lang.RT/uncheckedFloatCast x))
(defn unchecked-double
"Coerce to double. Subject to rounding."
{:inline (fn [x] `(. clojure.lang.RT (uncheckedDoubleCast ~x)))
:added "1.3"}
[^Number x] (clojure.lang.RT/uncheckedDoubleCast x))
(defn number?
"Returns true if x is a Number"
{:added "1.0"
:static true}
[x]
(instance? Number x))
(defn mod
"Modulus of num and div. Truncates toward negative infinity."
{:added "1.0"
:static true}
[num div]
(let [m (rem num div)]
(if (or (zero? m) (= (pos? num) (pos? div)))
m
(+ m div))))
(defn ratio?
"Returns true if n is a Ratio"
{:added "1.0"
:static true}
[n] (instance? clojure.lang.Ratio n))
(defn numerator
"Returns the numerator part of a Ratio."
{:tag BigInteger
:added "1.2"
:static true}
[r]
(.numerator ^clojure.lang.Ratio r))
(defn denominator
"Returns the denominator part of a Ratio."
{:tag BigInteger
:added "1.2"
:static true}
[r]
(.denominator ^clojure.lang.Ratio r))
(defn decimal?
"Returns true if n is a BigDecimal"
{:added "1.0"
:static true}
[n] (instance? BigDecimal n))
(defn float?
"Returns true if n is a floating point number"
{:added "1.0"
:static true}
[n]
(or (instance? Double n)
(instance? Float n)))
(defn rational?
"Returns true if n is a rational number"
{:added "1.0"
:static true}
[n]
(or (integer? n) (ratio? n) (decimal? n)))
(defn bigint
"Coerce to BigInt"
{:tag clojure.lang.BigInt
:static true
:added "1.3"}
[x] (cond
(instance? clojure.lang.BigInt x) x
(instance? BigInteger x) (clojure.lang.BigInt/fromBigInteger x)
(decimal? x) (bigint (.toBigInteger ^BigDecimal x))
(float? x) (bigint (. BigDecimal valueOf (double x)))
(ratio? x) (bigint (.bigIntegerValue ^clojure.lang.Ratio x))
(number? x) (clojure.lang.BigInt/valueOf (long x))
:else (bigint (BigInteger. x))))
(defn biginteger
"Coerce to BigInteger"
{:tag BigInteger
:added "1.0"
:static true}
[x] (cond
(instance? BigInteger x) x
(instance? clojure.lang.BigInt x) (.toBigInteger ^clojure.lang.BigInt x)
(decimal? x) (.toBigInteger ^BigDecimal x)
(float? x) (.toBigInteger (. BigDecimal valueOf (double x)))
(ratio? x) (.bigIntegerValue ^clojure.lang.Ratio x)
(number? x) (BigInteger/valueOf (long x))
:else (BigInteger. x)))
(defn bigdec
"Coerce to BigDecimal"
{:tag BigDecimal
:added "1.0"
:static true}
[x] (cond
(decimal? x) x
(float? x) (. BigDecimal valueOf (double x))
(ratio? x) (/ (BigDecimal. (.numerator ^clojure.lang.Ratio x)) (.denominator ^clojure.lang.Ratio x))
(instance? clojure.lang.BigInt x) (.toBigDecimal ^clojure.lang.BigInt x)
(instance? BigInteger x) (BigDecimal. ^BigInteger x)
(number? x) (BigDecimal/valueOf (long x))
:else (BigDecimal. x)))
(def ^:dynamic ^{:private true} print-initialized false)
(defmulti print-method (fn [x writer]
(let [t (get (meta x) :type)]
(if (keyword? t) t (class x)))))
(defmulti print-dup (fn [x writer] (class x)))
(defn pr-on
{:private true
:static true}
[x w]
(if *print-dup*
(print-dup x w)
(print-method x w))
nil)
(defn pr
"Prints the object(s) to the output stream that is the current value
of *out*. Prints the object(s), separated by spaces if there is
more than one. By default, pr and prn print in a way that objects
can be read by the reader"
{:dynamic true
:added "1.0"}
([] nil)
([x]
(pr-on x *out*))
([x & more]
(pr x)
(. *out* (append \space))
(if-let [nmore (next more)]
(recur (first more) nmore)
(apply pr more))))
(def ^:private ^String system-newline
(System/getProperty "line.separator"))
(defn newline
"Writes a platform-specific newline to *out*"
{:added "1.0"
:static true}
[]
(. *out* (append system-newline))
nil)
(defn flush
"Flushes the output stream that is the current value of
*out*"
{:added "1.0"
:static true}
[]
(. *out* (flush))
nil)
(defn prn
"Same as pr followed by (newline). Observes *flush-on-newline*"
{:added "1.0"
:static true}
[& more]
(apply pr more)
(newline)
(when *flush-on-newline*
(flush)))
(defn print
"Prints the object(s) to the output stream that is the current value
of *out*. print and println produce output for human consumption."
{:added "1.0"
:static true}
[& more]
(binding [*print-readably* nil]
(apply pr more)))
(defn println
"Same as print followed by (newline)"
{:added "1.0"
:static true}
[& more]
(binding [*print-readably* nil]
(apply prn more)))
(defn read
"Reads the next object from stream, which must be an instance of
java.io.PushbackReader or some derivee. stream defaults to the</