core: move distinct?/replace/nthnext/bounded-count/run!/completing to overlay

Fourth pure-fn batch (jolt-1j0 phase 2), 6 leaf fns. distinct? now uses
value-semantics (the prior Janet impl keyed a table by identity, so equal
collections compared distinct); nthnext uses the canonical loop form, which
fixes (nthnext nil nil) => nil and the nil-count cases the prior pre-check threw
on. replace preserves nil values via get-with-default.

conformance 218/218 x3, clojure-test-suite 3927 -> 3928 (canonical nthnext),
core-bench A/B flat. Per-batch gate caught a transient -1 from the first
nthnext rewrite; fixed before commit.
This commit is contained in:
Yogthos 2026-06-06 23:26:36 -04:00
parent b1daa4bcbd
commit 4aec21e603
2 changed files with 28 additions and 28 deletions

View file

@ -93,3 +93,31 @@
(defn drop-last (defn drop-last
([coll] (drop-last 1 coll)) ([coll] (drop-last 1 coll))
([n coll] (let [c (vec coll)] (subvec c 0 (max 0 (- (count c) n)))))) ([n coll] (let [c (vec coll)] (subvec c 0 (max 0 (- (count c) n))))))
(defn distinct?
([x] true)
([x y] (not (= x y)))
([x y & more]
(if (not (= x y))
(loop [s #{x y} xs more]
(if xs
(let [x (first xs)]
(if (contains? s x) false (recur (conj s x) (next xs))))
true))
false)))
(defn replace [smap coll] (mapv (fn [x] (get smap x x)) coll))
(defn nthnext [coll n]
(loop [n n xs (seq coll)]
(if (and xs (pos? n))
(recur (dec n) (next xs))
xs)))
(defn bounded-count [n coll] (min n (count coll)))
(defn run! [proc coll] (reduce (fn [_ x] (proc x) nil) nil coll) nil)
(defn completing
([f] (completing f identity))
([f cf] (fn ([] (f)) ([x] (cf x)) ([x y] (f x y)))))

View file

@ -3078,10 +3078,6 @@
start (max 0 (min n (length c)))] # negative n -> whole coll start (max 0 (min n (length c)))] # negative n -> whole coll
(tuple/slice (tuple ;(array/slice c start)))))) (tuple/slice (tuple ;(array/slice c start))))))
(defn core-nthnext [coll n]
(when (not (number? n)) (error "nthnext requires a numeric count"))
(let [r (core-nthrest coll n)] (if (or (nil? r) (= 0 (length r))) nil r)))
# filterv now lives in the Clojure collection tier (core/20-coll.clj). # filterv now lives in the Clojure collection tier (core/20-coll.clj).
# mapv lives in the Clojure kernel tier — core/00-kernel.clj. # mapv lives in the Clojure kernel tier — core/00-kernel.clj.
@ -3172,11 +3168,6 @@
(-- i)) (-- i))
(tuple/slice (tuple ;c)))) (tuple/slice (tuple ;c))))
(defn core-replace [smap coll]
(let [c (realize-for-iteration coll) r @[]]
(each x c (array/push r (let [v (core-get smap x :jolt/nf)] (if (= v :jolt/nf) x v))))
(tuple/slice (tuple ;r))))
# some-fn now lives in the Clojure collection tier (core/20-coll.clj). # some-fn now lives in the Clojure collection tier (core/20-coll.clj).
(defn core-sequential? [x] (or (tuple? x) (array? x) (pvec? x) (plist? x) (lazy-seq? x))) (defn core-sequential? [x] (or (tuple? x) (array? x) (pvec? x) (plist? x) (lazy-seq? x)))
@ -3190,10 +3181,6 @@
(and (struct? x) (= :symbol (x :jolt/type))))) (and (struct? x) (= :symbol (x :jolt/type)))))
(defn core-indexed? [x] (or (tuple? x) (array? x) (pvec? x))) (defn core-indexed? [x] (or (tuple? x) (array? x) (pvec? x)))
(defn core-distinct? [& xs]
(var seen @{}) (var ok true)
(each x xs (if (get seen x) (set ok false) (put seen x true)))
ok)
# With a single item, Clojure returns it WITHOUT calling f. On ties, the last # With a single item, Clojure returns it WITHOUT calling f. On ties, the last
# extremal item wins (>=/<= update), matching Clojure. # extremal item wins (>=/<= update), matching Clojure.
@ -3336,9 +3323,6 @@
(defn core-dorun [a & rest] (defn core-dorun [a & rest]
(let [coll (if (= 0 (length rest)) a (in rest 0))] (let [coll (if (= 0 (length rest)) a (in rest 0))]
(realize-for-iteration coll) nil)) (realize-for-iteration coll) nil))
(defn core-run! [f coll]
(each x (realize-for-iteration coll) (f x)) nil)
(defn core-tree-seq [branch? children root] (defn core-tree-seq [branch? children root]
(def out @[]) (def out @[])
(defn walk [node] (defn walk [node]
@ -3364,9 +3348,6 @@
(let [c (realize-for-iteration coll)] (let [c (realize-for-iteration coll)]
(in c (math/floor (* (math/random) (length c)))))) (in c (math/floor (* (math/random) (length c))))))
(defn core-bounded-count [n coll]
(let [c (realize-for-iteration coll)] (min n (length c))))
(defn core-counted? [x] (defn core-counted? [x]
(or (pvec? x) (plist? x) (phm? x) (set? x) (tuple? x) (array? x) (string? x))) (or (pvec? x) (plist? x) (phm? x) (set? x) (tuple? x) (array? x) (string? x)))
# Reversible (supports rseq) = vectors and sorted collections. # Reversible (supports rseq) = vectors and sorted collections.
@ -3412,9 +3393,6 @@
(defn core-comparator [pred] (defn core-comparator [pred]
(fn [a b] (cond (truthy? (pred a b)) -1 (truthy? (pred b a)) 1 true 0))) (fn [a b] (cond (truthy? (pred a b)) -1 (truthy? (pred b a)) 1 true 0)))
(defn core-completing [rf & cf]
(let [c (if (> (length cf) 0) (in cf 0) (fn [x] x))]
(fn [& a] (case (length a) 0 (rf) 1 (c (in a 0)) (rf (in a 0) (in a 1))))))
(defn core-keyword-identical? [a b] (= a b)) (defn core-keyword-identical? [a b] (= a b))
(defn core-object? [x] false) (defn core-object? [x] false)
(defn core-tagged-literal [tag form] @{:jolt/type :jolt/tagged-literal :tag tag :form form}) (defn core-tagged-literal [tag form] @{:jolt/type :jolt/tagged-literal :tag tag :form form})
@ -3658,13 +3636,11 @@
"apply" core-apply "apply" core-apply
"doall" core-doall "doall" core-doall
"dorun" core-dorun "dorun" core-dorun
"run!" core-run!
"tree-seq" core-tree-seq "tree-seq" core-tree-seq
"key" core-key "key" core-key
"val" core-val "val" core-val
"map-entry?" core-map-entry? "map-entry?" core-map-entry?
"rand-nth" core-rand-nth "rand-nth" core-rand-nth
"bounded-count" core-bounded-count
"counted?" core-counted? "counted?" core-counted?
"reversible?" core-reversible? "reversible?" core-reversible?
"seqable?" core-seqable? "seqable?" core-seqable?
@ -3686,7 +3662,6 @@
"future-cancel" core-future-cancel "future-cancel" core-future-cancel
"future-cancelled?" core-future-cancelled? "future-cancelled?" core-future-cancelled?
"comparator" core-comparator "comparator" core-comparator
"completing" core-completing
"keyword-identical?" core-keyword-identical? "keyword-identical?" core-keyword-identical?
"object?" core-object? "object?" core-object?
"tagged-literal" core-tagged-literal "tagged-literal" core-tagged-literal
@ -3744,16 +3719,13 @@
"reduced?" core-reduced? "reduced?" core-reduced?
"take-nth" core-take-nth "take-nth" core-take-nth
"nthrest" core-nthrest "nthrest" core-nthrest
"nthnext" core-nthnext
"empty" core-empty "empty" core-empty
"rseq" core-rseq "rseq" core-rseq
"shuffle" core-shuffle "shuffle" core-shuffle
"replace" core-replace
"sequential?" core-sequential? "sequential?" core-sequential?
"associative?" core-associative? "associative?" core-associative?
"ifn?" core-ifn? "ifn?" core-ifn?
"indexed?" core-indexed? "indexed?" core-indexed?
"distinct?" core-distinct?
"vary-meta" core-vary-meta "vary-meta" core-vary-meta
"ex-info" core-ex-info "ex-info" core-ex-info
"ex-data" core-ex-data "ex-data" core-ex-data