jolt/docs/spec/09-core-library.md
Yogthos 7003926eda docs: language specification RFC + spec skeleton with normative exemplars
RFC 0001 proposes a normative, implementation-independent Clojure language
spec (the reader, evaluation model, special forms, data types, seq/laziness
contracts, namespaces/vars, and the portable clojure.core surface) to the
standard of R7RS/Racket — Clojure has none, and every alternative
implementation re-derives semantics from the reference and folklore. The
spec is executable-first: every numbered normative statement cites its
conformance test or is marked UNVERIFIED.

docs/spec/ carries the front matter (conformance terms, entry format, host
classification), the special-form catalog with worked normative entries for
if and let*, the core-library entry format with worked entries for first,
reduce, and parse-uuid, and a generated coverage dashboard over the 694-var
ClojureDocs inventory (tools/spec_coverage.py cross-references the surface
against jolt's interned+resolvable vars and the test suites).

Measured baseline: 380 implemented+tested, 154 implemented-untested, 35
portable-but-missing (filed), 22 resolvable-but-not-interned (filed — seed
fns invisible to resolve/ns-publics), rest classified host/JVM/concurrency.
2026-06-10 10:53:44 -04:00

174 lines
6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# §9 The Core Library
**Status**: entry format fixed; exemplars for `first`, `reduce`, `parse-uuid`.
The full portable surface (≈500 vars after classification, dashboard in
`coverage.md`) is filled in chapter-by-chapter using this format.
Entries specify *behavioral contracts*, not implementations. Performance
characteristics are specified only where the language community relies on
them (e.g. vector `nth` is "effectively constant time" — SHOULD-level).
---
### first — since 1.0
```
(first coll)
```
**Semantics**
- S1. MUST return the first element of `(seq coll)`.
- S2. If `(seq coll)` is `nil` (i.e. `coll` is empty or `nil`), MUST return
`nil`.
- S3. MUST accept anything *seqable* (§5): seqs, lists, vectors, maps
(yielding map entries), sets, strings (yielding characters), `nil`.
- S4. On a lazy sequence, MUST realize at most the first element (§5
laziness contract).
**Edge cases**
- E1. `(first nil)``nil`; `(first [])``nil`; `(first "")``nil`.
- E2. A `nil` or `false` first *element* is returned as-is — callers cannot
distinguish "empty" from "first element is nil" via `first` alone (that is
what `seq` is for).
- E3. On a map, the element is a map entry; on an unordered collection (map,
set) *which* element is first is implementation-defined but MUST be
consistent with that collection's seq order for the same collection value.
**Errors**
- X1. A non-seqable argument (e.g. a number) MUST throw.
**Examples**
```clojure
(first [1 2 3]) ;=> 1
(first '()) ;=> nil
(first "ab") ;=> \a
(first {:a 1}) ;=> [:a 1]
(first [nil 2]) ;=> nil
```
**Conformance**
S1S3, E1E2 → jolt `sequences-spec` "seq / access"; clojure-test-suite
`core_test/first.cljc`. S4 → jolt `lazy-seqs-spec` counter cases. X1 →
clojure-test-suite `core_test/first.cljc` (throwing cases).
---
### reduce — since 1.0
```
(reduce f coll)
(reduce f init coll)
```
**Semantics**
- S1. With `init`: MUST return `init` if `(seq coll)` is nil; otherwise MUST
return `(f … (f (f init e₁) e₂) … eₙ)`, applying `f` left-to-right over the
elements, exactly once each.
- S2. Without `init`: if `coll` is empty, MUST return `(f)` (f called with
no arguments); if `coll` has one element, MUST return that element
*without calling `f`*; otherwise as S1 with `init = e₁` over `e₂…eₙ`.
- S3. **Reduced short-circuit**: if any intermediate result is a `reduced`
value, iteration MUST stop and the dereferenced value MUST be returned
immediately; `f` MUST NOT be called again.
- S4. `reduce` is eager: it MUST fully realize the consumed portion of a
lazy `coll` (to the end, or to the `reduced` point).
**Edge cases**
- E1. `(reduce f nil)``(f)`; `(reduce f init nil)``init`.
- E2. A `reduced` value as the *initial* `init` is NOT unwrapped before the
first call in the reference — ⚠ under-documented; differential result to
pin down and test before this entry is marked verified.
- E3. Visit order over maps is entry order of the map's seq;
over vectors/lists/seqs it is sequential order (normative).
**Errors**
- X1. Without `init`, on an empty coll, if `f` has no zero-arg arity the
call `(f)` MUST throw (arity error).
**Examples**
```clojure
(reduce + [1 2 3 4]) ;=> 10
(reduce + 10 [1 2 3 4]) ;=> 20
(reduce + []) ;=> 0 ; (+) is 0
(reduce + [5]) ;=> 5 ; f not called
(reduce (fn [a x] (if (> a 2) (reduced a) (+ a x))) 0 [1 2 3 4 5]) ;=> 3
```
**Conformance**
S1S3, E1 → jolt `sequences-spec` "map filter reduce" group +
`transducers-spec` "reduce honors reduced"; clojure-test-suite
`core_test/reduce.cljc`. S2 (single-element, f-not-called) → jolt conformance
"reduce single no init". E2 → UNVERIFIED (differential test to add). S4 →
`lazy-seqs-spec`.
---
### parse-uuid — since 1.11
```
(parse-uuid s)
```
**Semantics**
- S1. If `s` is a string in canonical UUID form — five groups of hex digits
of lengths 8, 4, 4, 4, 12 separated by `-` — MUST return a UUID value `u`
such that `(uuid? u)` is true and `(str u)` is the lowercase form of `s`.
- S2. Parsing MUST be case-insensitive and equality on the results
case-insensitive: `(= (parse-uuid s) (parse-uuid (upper-case s)))` is true.
- S3. If `s` is a string not in canonical form, MUST return `nil`.
⚠ reference-divergence: reference Clojure (java.util.UUID) additionally
accepts non-canonical forms like `"0-0-0-0-0"`; ClojureScript and other
dialects are strict. This spec adopts **strict** (the cross-dialect
behavior); the reference's permissiveness is recorded as host leniency.
- S4. UUID values MUST support value equality, hashing (usable as map keys
and set members), `str` (lowercase canonical form), and print as the
tagged literal `#uuid "…"` such that the printed form reads back equal
(§2 tagged literals).
**Edge cases**
- E1. `""`, over-long, truncated, non-hex characters, and misplaced dashes
`nil`.
**Errors**
- X1. A non-string argument MUST throw.
**Examples**
```clojure
(parse-uuid "b6883c0a-0342-4007-9966-bc2dfa6b109e") ;=> #uuid "b6883c0a-…"
(uuid? *1) ;=> true
(parse-uuid "df0993") ;=> nil
(parse-uuid 1000) ;; throws
```
**Conformance**
S1S4, E1, X1 → jolt `uuid-spec` (30 cases) + 6 three-path conformance
cases; clojure-test-suite `core_test/parse_uuid.cljc`,
`core_test/uuid_qmark.cljc`, `core_test/random_uuid.cljc`.
---
## Authoring notes
- Source examples from the ClojureDocs export (`clojuredocs-export.edn`,
648 core vars have community examples) — but every example is verified
against the reference before inclusion.
- When writing an entry surfaces a behavior question, settle it by
differential test first; if dialects split, that's a classification
decision (host-dependent / divergence note), not a coin flip.
- An entry is **Verified** when no field carries UNVERIFIED; `coverage.md`
tracks per-var status.