diff --git a/jolt-core/clojure/core/40-lazy.clj b/jolt-core/clojure/core/40-lazy.clj index 4b981b7..d5e866c 100644 --- a/jolt-core/clojure/core/40-lazy.clj +++ b/jolt-core/clojure/core/40-lazy.clj @@ -3,17 +3,26 @@ ;; ;; Each fn ported from CLJS core.cljs, stripped of chunked-seq branches. -;; --- distinct --- -(defn distinct [coll] - (let [step (fn step [xs seen] - (lazy-seq - ((fn [[f :as xs] seen] - (when-let [s (seq xs)] - (if (contains? seen f) - (recur (rest s) seen) - (cons f (step (rest s) (conj seen f)))))) - xs seen)))] - (step coll #{}))) +;; --- distinct --- (transducer + lazy collection arity; value-based dedup) +(defn distinct + ([] + (fn [rf] + (let [seen (volatile! #{})] + (fn ([] (rf)) ([result] (rf result)) + ([result input] + (if (contains? @seen input) + result + (do (vswap! seen conj input) (rf result input)))))))) + ([coll] + (let [step (fn step [xs seen] + (lazy-seq + ((fn [[f :as xs] seen] + (when-let [s (seq xs)] + (if (contains? seen f) + (recur (rest s) seen) + (cons f (step (rest s) (conj seen f)))))) + xs seen)))] + (step coll #{})))) ;; --- keep --- @@ -76,10 +85,10 @@ (cstep 0))) ())) -;; --- repeatedly --- -(defn repeatedly - ([f] (lazy-seq (cons (f) (repeatedly f)))) - ([n f] (take n (repeatedly f)))) +;; repeatedly stays in the Janet seed for now (core-repeatedly): the canonical CLJ +;; version doesn't validate args, so (first (repeatedly non-fn)) / (repeatedly \a +) +;; don't throw like the stricter Janet version (repeatedly.cljc throw cases). +;; Ported separately once the non-fn / non-number-count throws are matched. ;; --- repeat --- (defn repeat @@ -91,10 +100,7 @@ (lazy-seq (cons x (iterate f (f x))))) -;; --- partition-all --- -(defn partition-all - ([n coll] (partition-all n n coll)) - ([n step coll] - (lazy-seq - (when-let [s (seq coll)] - (cons (take n s) (partition-all n step (nthrest coll step))))))) +;; partition-all stays in the Janet seed for now (core-partition-all): it already +;; has the transducer + collection arities (jolt-cru), and a CLJ port realizes a +;; different (non-minimal) element count via take/drop than the Janet one, +;; tripping the §6.3 laziness counters + a suite file. Ported separately. diff --git a/src/jolt/api.janet b/src/jolt/api.janet index e3af642..b97fa28 100644 --- a/src/jolt/api.janet +++ b/src/jolt/api.janet @@ -53,7 +53,8 @@ {:ns "clojure.core.00-kernel" :kernel true} {:ns "clojure.core.10-seq" :kernel false} {:ns "clojure.core.20-coll" :kernel false} - {:ns "clojure.core.30-macros" :kernel false}]) + {:ns "clojure.core.30-macros" :kernel false} + {:ns "clojure.core.40-lazy" :kernel false}]) (defn- eval-overlay-source [ctx src] (var s src) diff --git a/src/jolt/core.janet b/src/jolt/core.janet index 4301997..0dfa53e 100644 --- a/src/jolt/core.janet +++ b/src/jolt/core.janet @@ -804,9 +804,7 @@ (fn [rf] (fn [& a] (case (length a) 0 (rf) 1 (rf (a 0)) (if (truthy? (pred (a 1))) (rf (a 0) (a 1)) (a 0)))))) (defn td-remove [pred] (td-filter (fn [x] (not (pred x))))) -(defn td-keep [f] - (fn [rf] (fn [& a] (case (length a) 0 (rf) 1 (rf (a 0)) - (let [v (f (a 1))] (if (nil? v) (a 0) (rf (a 0) v))))))) +# td-keep removed: keep (incl its transducer arity) lives in core/40-lazy.clj. (defn td-take [n] (fn [rf] (var left n) @@ -829,10 +827,7 @@ (fn [& a] (case (length a) 0 (rf) 1 (rf (a 0)) (do (when (and dropping (not (truthy? (pred (a 1))))) (set dropping false)) (if dropping (a 0) (rf (a 0) (a 1)))))))) -(defn td-map-indexed [f] - (fn [rf] - (var i -1) - (fn [& a] (case (length a) 0 (rf) 1 (rf (a 0)) (do (++ i) (rf (a 0) (f i (a 1)))))))) +# td-map-indexed removed: map-indexed (incl transducer arity) lives in core/40-lazy.clj. # Stateful windowing transducers. The 1-arg (completion) arity flushes a partial # trailing window before delegating to rf's completion; matches Clojure. @@ -1342,22 +1337,7 @@ (sort-by keyfn arr)) (tuple/slice (tuple ;arr)))))) -(defn core-distinct [coll] - # Option A: always lazy. seen-set is captured once and shared across the chain. - (let [seen @{}] - (defn dstep [c] - (fn [] - (var cur c) (var found false) (var result nil) - (while (and (not found) (not (seq-done? cur))) - (let [x (core-first cur)] - (set cur (core-rest cur)) - (when (nil? (seen x)) - (put seen x true) - (set found true) - (set result x)))) - (if found @[result (dstep cur)] nil))) - (make-lazy-seq (dstep (lazy-from coll))))) - +# distinct now lives in the Clojure lazy tier (core/40-lazy.clj). # group-by / frequencies now live in the Clojure collection tier # (core/20-coll.clj). @@ -1384,21 +1364,7 @@ nil))))) (make-lazy-seq (pstep (lazy-from coll))))) -(defn core-partition-by [f coll] - (def f (as-fn f)) - (var result @[]) - (var part @[]) - (var last-k nil) - (each x (realize-for-iteration coll) - (let [k (f x)] - (if (and last-k (deep= k last-k)) - (array/push part x) - (do - (if (> (length part) 0) (array/push result (tuple/slice (tuple ;part)))) - (set part @[x]) - (set last-k k))))) - (if (> (length part) 0) (array/push result (tuple/slice (tuple ;part)))) - result) +# partition-by now lives in the Clojure seq tier (core/10-seq.clj). (defn core-partition-all [n & rest] (if (= 0 (length rest)) (td-partition-all n) @@ -1417,39 +1383,8 @@ (make-lazy-seq (pstep (lazy-from coll)))))) -(defn core-keep-indexed [f coll] - (def f (as-fn f)) - # Option A: always lazy. - (defn kstep [c i] - (fn [] - (var cur c) (var idx i) (var found false) (var result nil) - (while (and (not found) (not (seq-done? cur))) - (let [v (f idx (core-first cur))] - (++ idx) - (set cur (core-rest cur)) - (when (not (nil? v)) - (set found true) - (set result v)))) - (if found @[result (kstep cur idx)] nil))) - (make-lazy-seq (kstep (lazy-from coll) 0))) - -(defn core-map-indexed [f & rest] - (if (= 0 (length rest)) (td-map-indexed f) - (let [coll (in rest 0)] - # Option A: always lazy. - (defn mstep [c i] - (fn [] - (if (seq-done? c) nil - @[(f i (core-first c)) (mstep (core-rest c) (+ i 1))]))) - (make-lazy-seq (mstep (lazy-from coll) 0))))) - -(defn core-cycle [coll] - (let [c (realize-for-iteration coll)] - (if (= 0 (length c)) - (make-lazy-seq (fn [] nil)) - (do - (defn cstep [i] (fn [] @[(in c (% i (length c))) (cstep (+ i 1))])) - (make-lazy-seq (cstep 0)))))) +# keep-indexed / map-indexed / cycle now live in the Clojure lazy tier +# (core/40-lazy.clj). # reduce-kv now lives in the Clojure collection tier (core/20-coll.clj). @@ -1495,20 +1430,7 @@ (+= i step)) (tuple/slice (tuple ;result)))))) -(defn core-repeat - "(repeat x) -> infinite lazy seq of x; (repeat n x) -> n copies of x." - [a & rest] - (if (= 0 (length rest)) - (do (defn rstep [] (fn [] @[a (rstep)])) (make-lazy-seq (rstep))) - (let [n a x (in rest 0)] - (var result @[]) (var i 0) - (while (< i n) (array/push result x) (++ i)) - result))) - -(defn core-iterate [f x] - "Lazy infinite sequence x, (f x), (f (f x)), ..." - (defn istep [v] (fn [] @[v (istep (f v))])) - (make-lazy-seq (istep x))) +# repeat / iterate now live in the Clojure lazy tier (core/40-lazy.clj). (defn core-repeatedly "(repeatedly f) -> infinite lazy seq of (f) calls; (repeatedly n f) -> n calls." @@ -2408,26 +2330,7 @@ @[(core-first c) (istep (core-rest c) true)])))) (make-lazy-seq (istep (lazy-from coll) false))))) -(defn core-keep - "(keep f coll) — (f x) for each x, dropping nils. (keep f) is a transducer." - [f & rest] - (def f (as-fn f)) - (if (= 0 (length rest)) - (td-keep f) - (let [coll (in rest 0)] - # Option A: always lazy. - (defn kstep [c] - (fn [] - (var cur c) (var found false) (var result nil) - (while (and (not found) (not (seq-done? cur))) - (let [v (f (core-first cur))] - (set cur (core-rest cur)) - (when (not (nil? v)) - (set found true) - (set result v)))) - (if found @[result (kstep cur)] nil))) - (make-lazy-seq (kstep (lazy-from coll)))))) - +# keep now lives in the Clojure lazy tier (core/40-lazy.clj). (defn core-empty [coll] (cond @@ -2517,14 +2420,7 @@ # Iterator/enumeration seqs — Jolt has no Java iterators, so adapt to plain seq. (defn core-enumeration-seq [x] (core-seq x)) (defn core-iterator-seq [x] (core-seq x)) -(defn core-xml-seq [root] - (def out @[]) - (defn walk [n] - (array/push out n) - (when (and (core-map? n) (core-contains? n :content)) - (each c (realize-for-iteration (core-get n :content)) (walk c)))) - (walk root) - (tuple ;out)) +# xml-seq now lives in the Clojure collection tier (core/20-coll.clj). (defn core-line-seq [rdr] (if (string? rdr) (core-seq (string/split "\n" rdr)) nil)) (defn core-re-matcher [re s] @{:jolt/type :jolt/matcher :re re :s s :pos 0}) @@ -2867,9 +2763,6 @@ "contains?" core-contains? "count" core-count "partition-all" core-partition-all - "keep-indexed" core-keep-indexed - "map-indexed" core-map-indexed - "cycle" core-cycle "pop" core-pop "trampoline" core-trampoline "format" core-format @@ -2952,7 +2845,6 @@ "random-uuid" core-random-uuid "interpose" core-interpose "mapcat" core-mapcat - "keep" core-keep "find" core-find "transduce" core-transduce "sequence" core-sequence @@ -2990,12 +2882,8 @@ "nth" core-nth "sort" core-sort "sort-by" core-sort-by - "distinct" core-distinct "partition" core-partition - "partition-by" core-partition-by "range" core-range - "repeat" core-repeat - "iterate" core-iterate "repeatedly" core-repeatedly "identity" core-identity "constantly" core-constantly @@ -3103,7 +2991,6 @@ "test" core-test "enumeration-seq" core-enumeration-seq "iterator-seq" core-iterator-seq - "xml-seq" core-xml-seq "line-seq" core-line-seq "re-matcher" core-re-matcher "bean" core-bean