1 Introduction
1.1 Overview
std.lib.foundation provides basic predicates, constructors, and helpers used across the foundation libraries.
2 Walkthrough
2.1 Constants and combinators
T, F, and NIL are constant functions. U and Z are classic fixed-point combinators, useful for anonymous recursion.
constant functions and combinators
^{:refer std.lib.foundation/T :added "3.0"}
(T 1 2 3)
=> true
^{:refer std.lib.foundation/F :added "3.0"}
(F 1 2 3)
=> false
^{:refer std.lib.foundation/Z :added "3.0"}
(let [factorial (fn [f]
(fn [n]
(if (zero? n)
1
(* n (f (dec n))))))]
((Z factorial) 5))
=> 120
2.2 Identifiers and time
Generate short IDs, UUIDs, and timestamps.
create identifiers and instants
^{:refer std.lib.foundation/sid :added "3.0"}
(sid)
=> string?
^{:refer std.lib.foundation/uuid :added "3.0"}
(uuid)
=> #(instance? java.util.UUID %)
^{:refer std.lib.foundation/instant :added "3.0"}
(instant 0)
=> #inst "1970-01-01T00:00:00.000-00:00"
2.3 Coercion helpers
strn, keyword, and string coerce values to common types.
coerce values
^{:refer std.lib.foundation/strn :added "3.0"}
(strn :hello)
=> "hello"
^{:refer std.lib.foundation/keyword :added "3.0"}
(keyword "hello")
=> :hello
^{:refer std.lib.foundation/string :added "3.0"}
(string (.getBytes "Hello"))
=> "Hello"
3 Constants and Combinators
v 3.0
(defn T
([& args]
true))
link
(T) => true (T :hello) => true (T 1 2 3) => true 1 => (capture odd?)
v 3.0
(defn U
([f] (fn [x] ((f f) x))))
link
(let [factorial (fn [f] (fn [n] (if (zero? n) 1 (* n ((f f) (dec n))))))] ((U factorial) 5)) => 120
v 3.0
(defn Z
([f] (let [A (fn [x] (f (U x)))] (A A))))
link
(let [factorial (fn [f] (fn [n] (if (zero? n) 1 (* n (f (dec n))))))] ((Z factorial) 5) => 120) ;; The body of Z can be defined as (defn- U1 ([f] (fn [x] (f (U x))))) ;; For the record, the Y combinator ;; can be defined as follows (defn- U0 ([f] (fn [x] (f (x x))))) (defn Y ([f] (let [A (U0 f)] (A A))))
4 Identifiers
sid, uuid, and flake generate short and unique identifiers.
v 3.0
(defn flake
([]
(str (Flake/flake))))
link
(flake) ;; "4Wv-T47LftnVlHhhh00JYuU15NCuNLcr" => string?
v 3.0
(defn sid
([]
(clojure.core/-> (str (java.util.UUID/randomUUID))
(.getBytes)
(java.nio.ByteBuffer/wrap)
(.getLong)
(Long/toString Character/MAX_RADIX))))
link
(sid) ;; "t8a6euzk9usy" => string?
v 3.0
(defn uuid
([] (java.util.UUID/randomUUID))
([id]
(cond (string? id)
(java.util.UUID/fromString id)
(instance? (Class/forName "[B") id)
(java.util.UUID/nameUUIDFromBytes id)
(keyword? id)
(java.util.UUID. (.hashCode ^Object id)
(.hashCode (name id)))
:else
(throw (ex-info (str id " can only be a string or byte array")))))
([^Long msb ^Long lsb]
(java.util.UUID. msb lsb)))
link
(uuid) => #(instance? java.util.UUID %) (uuid "00000000-0000-0000-0000-000000000000") => #uuid "00000000-0000-0000-0000-000000000000"
5 Constructors
Construct common Java and Clojure values.
v 3.0
(defn date
([] (Date.))
([^long t] (Date. t)))
link
(date 1000) => #inst "1970-01-01T00:00:01.000-00:00"
v 3.0
(defn instant
([] (java.util.Date.))
([^Long val] (java.util.Date. val)))
link
(instant) => #(instance? java.util.Date %) (instant 0) => #inst "1970-01-01T00:00:00.000-00:00"
6 Coercion
v 3.0
(defn edn
([obj]
(read-string (pr-str obj))))
link
((juxt type (comp type edn)) (symbol ":hello")) => [clojure.lang.Symbol clojure.lang.Keyword]
v 3.0
(defn edn?
([x]
(or (nil? x)
(boolean? x)
(string? x)
(char? x)
(symbol? x)
(keyword? x)
(number? x)
(seq? x)
(vector? x)
(record? x)
(map? x)
(set? x)
(tagged-literal? x)
(var? x)
(regexp? x))))
link
(edn? 1) => true (edn? {}) => true (edn? (java.util.Date.)) => false
v 3.0
(defn keyword
([obj]
(cond (keyword? obj)
obj
(string? obj)
(clojure.core/keyword obj)
:else
(throw (ex-info "Cannot process obj" {:input obj})))))
link
(keyword :hello) => :hello (keyword "hello") => :hello
v 3.0
(defn string
([obj]
(cond (bytes? obj)
(String. ^bytes obj)
:else
(str obj))))
link
(string (.getBytes "Hello")) => "Hello"
7 Type Predicates
- array?
- atom?
- bigdec?
- bigint?
- byte?
- comparable?
- ideref?
- iobj?
- iref?
- long?
- regexp?
- short?
- thread?
- url?
v 3.0
(defn array?
([x]
(.isArray ^Class (type x)))
([cls x]
(and (array? x)
(= cls (.getComponentType ^Class (type x))))))
link
(array? (into-array [])) => true (array? String (into-array ["a" "b" "c"])) => true
v 3.0
(defn bigdec?
([x]
(instance? java.math.BigDecimal x)))
link
(bigdec? 1M) => true (bigdec? 1.0) => false
v 3.0
(defn bigint?
([x]
(instance? clojure.lang.BigInt x)))
link
(bigint? 1N) => true (bigint? 1) => false
comparable? ^
[x y]
returns `true` if `x` and `y` both implements `java.lang.Comparable`.
v 3.0
(defn comparable?
([x y]
(and (instance? Comparable x)
(instance? Comparable y)
(= (type x) (type y)))))
link
(comparable? 1 1) => true
v 3.0
(defn ideref?
([obj]
(instance? clojure.lang.IDeref obj)))
link
(ideref? (volatile! 0)) => true (ideref? (promise)) => true
v 3.0
(defn iref?
([obj]
(instance? clojure.lang.IRef obj)))
link
(iref? (atom 0)) => true (iref? (ref 0)) => true (iref? (agent 0)) => true (iref? (volatile! 0)) => false (iref? (promise)) => false (iref? (clojure.core/future)) => false
8 Parsing
9 Invocation
call ^
[obj] [obj f] [obj f v1] [obj f v1 v2] [obj f v1 v2 v3] [obj f v1 v2 v3 v4] [obj f v1 v2 v3 v4 & vs]
like `invoke` but reverses the function and first argument
v 3.0
(defn call
([obj] obj)
([obj f] (if (nil? f) obj (f obj)))
([obj f v1] (if (nil? f) obj (f obj v1)))
([obj f v1 v2] (if (nil? f) obj (f obj v1 v2)))
([obj f v1 v2 v3] (if (nil? f) obj (f obj v1 v2 v3)))
([obj f v1 v2 v3 v4] (if (nil? f) obj (f obj v1 v2 v3 v4)))
([obj f v1 v2 v3 v4 & vs] (if (nil? f) obj (apply f obj v1 v2 v3 v4 vs))))
link
(call 2) => 2 (call 2 + 1 2 3) => 8
10 Errors
v 3.0
(defmacro error
([message]
`(throw (ex-info ~message {})))
([message data]
`(throw (ex-info ~message ~data))))
link
(error "Error") => (throws)
v 3.0
(defmacro suppress
([body]
`(try ~body (catch Throwable ~'t)))
([body catch-val]
`(try ~body (catch Throwable ~'t
(cond (fn? ~catch-val)
(~catch-val ~'t)
:else ~catch-val)))))
link
(suppress (throw (ex-info "Error" {}))) => nil (suppress (throw (ex-info "Error" {})) :error) => :error (suppress (throw (ex-info "Error" {})) (fn [^Throwable e] (.getMessage e))) => "Error"
v 3.0
(defn throwable?
([obj]
(instance? Throwable obj)))
link
(throwable? (ex-info "hello" {})) => true
11 Utilities
v 3.0
(defn aget
([arr i]
(case (.getName ^Class (type arr))
"[J" (clojure.core/aget ^longs arr i)
"[I" (clojure.core/aget ^ints arr i)
"[S" (clojure.core/aget ^shorts arr i)
"[B" (clojure.core/aget ^bytes arr i)
"[Z" (clojure.core/aget ^booleans arr i)
"[F" (clojure.core/aget ^floats arr i)
"[D" (clojure.core/aget ^doubles arr i))))
link
(aget (int-array [1 2 3]) 2) => 3
v 3.0
(defn demunge
([name]
(clojure.lang.Compiler/demunge name)))
link
(demunge ;;; (munge "+test!") "_PLUS_test_BANG_") => "+test!"
v 3.0
(defn hash-id
([obj]
(System/identityHashCode obj)))
link
(hash-id {}) => (hash-id {}) (= (hash-id {:a 1}) (hash-id {:a 1})) => false (hash-id "1") => (hash-id "1")
12 std.lib.foundation Recommendations
std.lib.foundation provides the most basic utility functions for the entire foundation-base ecosystem. Its goal is to be a lightweight, universal "prelude" for all other modules. Here are some recommendations for new functionality that would align with this goal and further enhance the developer experience.
- More String Utilities:n Justification: String manipulation is a very common task. While
std.string.commonexists,std.lib.foundationwould benefit from having a few core, frequently used string functions directly available. This would reduce the need for other modules to importstd.string.common, simplifying dependencies and improving code readability.n Recommendations:ntrim: Removes leading and trailing whitespace from a string.nsplit: Splits a string into a sequence of strings based on a delimiter.njoin: Joins a sequence of strings into a single string with a separator.nreplace: Replaces all occurrences of a substring or pattern with another string.nstarts-with?,ends-with?: Checks if a string starts or ends with a given prefix or suffix.n Example Usage:n ```clojuren (-> " hello world " h/trim (h/split #" ") (h/join "-"))n ;; => "hello-world"n ```nn Enhanced Type Checking:n Justification: The codebase already has predicates likestring?,keyword?, andsymbol?. Expanding this set would provide a more complete and consistent way to perform type checks, which is especially useful for validation and multi-method dispatch.n Recommendations:nmapp?: Checks if an object is a map.nvector?: Checks if an object is a vector.nset?: Checks if an object is a set.nfn?: Checks if an object is a function.ncoll?: Checks if an object is a collection (list, vector, set, or map).n Example Usage:n ```clojuren (when (h/mapp? my-data)n (h/map-vals process-value my-data))n ```nn More Math Functions:n Justification: While the project has amathnamespace, some very basic math functions are so common that they would be a good fit forstd.lib.foundation.n Recommendations:nabs: Returns the absolute value of a number.nmin,max: Returns the minimum or maximum of a set of numbers.nround,floor,ceil: For rounding numbers.n Example Usage:n ```clojuren (h/round 3.14159) ;; => 3n (h/max 1 5 2 8 3) ;; => 8n ```nnidentityfunction:n Justification: Theidentityfunction is a fundamental building block in functional programming. It's often used as a default function or in higher-order functions. Its absence is a noticeable omission.n Recommendation: Add(defn identity [x] x).n Example Usage:n ```clojuren (get-in my-map [:a :b] :default-value)n ;; vsn (-> (get-in my-map [:a :b]) (or :default-value))n ;; with identityn (-> (get-in my-map [:a :b]) (h/call identity) (or :default-value))n ```nnconstantlyfunction:n Justification:constantlyis another useful higher-order function that creates a function that always returns the same value. It's great for stubbing out functions or for use with functions likemap.n Recommendation: Add(defn constantly [x] (fn [& args] x)).n Example Usage:n ```clojuren (map (h/constantly 0) (range 5)) ;; => (0 0 0 0 0)n ```nnjuxtfunction:n Justification:juxtis a powerful function for applying multiple functions to the same arguments and collecting the results. It can simplify code and make it more expressive.n Recommendation: Add ajuxtimplementation.n Example Usage:n ```clojuren (let [stats (h/juxt min max count)]n (stats [1 5 2 8 3])) ;; => [1 8 5]n ```
13 std.lib.foundation: A Comprehensive Summary
The std.lib.foundation namespace is a foundational utility library within the foundation-base ecosystem, providing a wide array of functions and macros that serve as core building blocks for other modules. It extends, re-implements, or introduces new functionalities for common programming tasks, with a strong emphasis on low-level operations, type checking, meta-programming, and interoperability.
Key Features and Concepts (Summarizing all public symbols):
- Core Constants and Basic Utilities:n
+init+: A var holdingfind-ns, likely used for initialization or namespace lookup.n*sep*: A dynamic var for a separator string, defaulting to "/".nT: A function that always returnstrue, regardless of arguments.nF: A function that always returnsfalse, regardless of arguments.nNIL: A function that always returnsnil, regardless of arguments.nxor: A macro for performing an exclusive OR comparison between two boolean values.nn2. Unique Identifiers and Time:nsid: Generates a short, unique ID string.nsid-tag: A memoized function to generate a short ID string based on a tag.nuuid: Creates ajava.util.UUIDobject from various inputs (random, string, byte array, keyword, or twoLongs).nuuid-nil: Constructs a nil UUID (all zeros).ninstant: Returns ajava.util.Dateobject, either current or from aLongtimestamp.nuri: Creates ajava.net.URIobject from a path string.nurl: Creates ajava.net.URLobject from a path string.ndate: Creates ajava.util.Dateobject, either current or from alongtimestamp.nflake: Returns a unique, time-incremental ID string usinghara.lib.foundation.Flake.nn3. String and Data Manipulation:nstrn: Converts various types (bytes, keyword, string) to a string, orpr-strfor others. Can concatenate multiple arguments.nlsubs: Returns a substring from the beginning, excludingncharacters from the end.nkeyword: Converts a string or keyword to a keyword.nstring: Converts a byte array to a string, orstrfor other types.nconcatv: Concatenates multiple sequences into a single vector.nedn: Prints an object to a string and then reads it back, useful for serialization/deserialization testing.nn4. Combinators:nU: The U combinator, enabling recursive function definitions.nZ: The Z combinator, also for recursive function definitions.nn5. Counters:ncounter: Creates a mutable counter object (hara.lib.foundation.Counter).ninc!: Increments a counter by 1 or a specified amount.ndec!: Decrements a counter by 1 or a specified amount.nreset!: Resets a counter to a given value.nn6. Function Invocation and Macros:ninvoke: Invokes aclojure.lang.IFnwith arguments.ncall: Similar toinvoke, but reverses the function and first argument, allowing for a threading-like style.nconst: A macro that evaluates its body at compile time, effectively creating a constant.napplym: A macro that allows applying other macros to arguments, similar toapplyfor functions.nn7. Code Context and Threading Macros:ncode-ns: Returns the symbol of the current namespace where the code is located.ncode-line: Returns the line number of the current code form.ncode-column: Returns the column number of the current code form.nthread-form: A helper function for->and->>macros.n->: A threading macro similar toclojure.core/->, but uses%as a placeholder for the threaded value, offering more flexibility.n->>: A threading macro similar toclojure.core/->>, also using%as a placeholder.nn8. Var and Symbol Management:nvar-sym: Converts aclojure.lang.Varto its fully qualified symbol.nunbound?: Checks if a var is currently unbound.nset!: A macro to set the value of a var without altering its metadata, providing a controlled way to re-define vars.nn9. Error Handling and Debugging:nsuppress: A macro that executes a body of code and suppresses anyThrowableexceptions, optionally returning a default value or applying a handler function to the exception.nwith-thrown: A macro that executes a body and returns anyThrowablecaught, otherwise returns the result of the body.nwith-ex: A macro that executes a body and returns theex-dataof anyThrowablecaught, otherwise returns the result of the body.nwith-retry-fn: A function that retries a given functionfa specifiedlimitnumber of times, with asleepinterval between retries, until it succeeds or the limit is reached.nwith-retry: A macro wrapper aroundwith-retry-fnfor convenient retry logic.nerror: A macro to throw anex-infowith a message and optional data.ntrace: A macro that returns aThrowablecontaining a stack trace, useful for debugging code paths.nthrowable?: A predicate to check if an object is an instance ofjava.lang.Throwable.nn10. Type Predicates:nbyte?: Checks if an object is ajava.lang.Byte.nshort?: Checks if an object is ajava.lang.Short.nlong?: Checks if an object is ajava.lang.Long.nbigint?: Checks if an object is aclojure.lang.BigInt.nbigdec?: Checks if an object is ajava.math.BigDecimal.nregexp?: Checks if an object is ajava.util.regex.Pattern.niobj?: Checks if an object implementsclojure.lang.IObj.niref?: Checks if an object implementsclojure.lang.IRef(e.g.,Atom,Ref,Agent).nideref?: Checks if an object implementsclojure.lang.IDeref(e.g.,volatile!,promise).nthread?: Checks if an object is ajava.lang.Thread.nurl?: Checks if an object is ajava.net.URL.natom?: Checks if an object is aclojure.lang.Atom.ncomparable?: Checks if two objects are bothComparableand of the same type.narray?: Checks if an object is a primitive array, optionally checking its component type.nedn?: Checks if an object is a valid EDN (Extensible Data Notation) value.nn11. Parsing and Hashing:nparse-long: Parses a string into aLong.nparse-double: Parses a string into aDouble.nhash-id: Returns the identity hash code of an object (memory address-based).nhash-code: Returns the standardhashCodeof an object.nn12. Array Access:naget: A type-safe version ofclojure.core/agetfor primitive arrays (e.g.,longs,ints,bytes).nn13. Namespace and Var Interning (Meta-programming):ndemunge: Demunges a Java-mangled name back to its original Clojure form.nre-create: A memoized function to create ajava.util.regex.Patternfrom a string, escaping special characters.nintern-var: Interns a var into a specified namespace, optionally merging metadata.nintern-form: A helper function to create the form forintern-var.nintern-in: A macro to intern specific vars from other namespaces into the current one.nintern-all: A macro to intern all public vars from one or more namespaces into the current one.nn14. Templating Macros (Advanced Meta-programming):n*template-meta*: A dynamic var for binding template metadata.nwith:template-meta: A macro to bind*template-meta*for a block of code.ntemplate-meta: Returns the currently bound template metadata.ntemplate-vars: A macro to generate multiple var definitions using a template function and a list of symbols/arguments.ntemplate-entries: A macro to generate entries using a template function and a list of data entries, supporting resolution of symbols and lists.ntemplate-bulk: Similar totemplate-entriesbut optimized for heavy usage, applyingevalto the template function's output.ntemplate-ensure: A helper function to verify that templated entries match the actual interned vars, useful for consistency checks.nn15. Wrapped Objects:nWrapped: Adeftypefor wrapping values, primarily for display purposes, allowing customtoStringbehavior.nwrapped: Creates aWrappedobject.nwrapped?: Checks if an object is aWrappedinstance.nn16. Namespaced Symbol Resolution:nresolve-namespaced: Resolves a namespaced symbol to its fully qualified var symbol.nn17. Multiple Var Definition:ndef.m: A macro to define multiple vars from the elements of a sequence returned by a single call.
Usage and Importance:
std.lib.foundation is a critical component of the foundation-base project, serving as its low-level utility belt. Its functions and macros are designed to:
- Enhance Clojure Core: Provide more robust or specialized versions of common Clojure functionalities.n Facilitate Interoperability: Offer seamless integration with Java types and features.n Support Meta-programming: Enable powerful code generation, introspection, and transformation, which is essential for the project's transpilation and runtime management goals.n Improve Debugging and Development: Provide tools for unique ID generation, precise timing, error handling, and code context retrieval.n Ensure Type Safety: Offer a comprehensive set of type predicates and type-aware operations.
By consolidating these fundamental capabilities, std.lib.foundation provides a stable and extensible base upon which the rest of the foundation-base ecosystem is built, contributing significantly to its flexibility, performance, and maintainability.