diff --git a/jolt-core/clojure/core/10-seq.clj b/jolt-core/clojure/core/10-seq.clj index f5c0fa3..91e84e5 100644 --- a/jolt-core/clojure/core/10-seq.clj +++ b/jolt-core/clojure/core/10-seq.clj @@ -22,3 +22,15 @@ (if (next s) (recur (conj ret (first s)) (next s)) (seq ret)))) + +;; Lazy partition-by: groups consecutive elements by (f x), matching Clojure/CLJS. +(defn partition-by [f coll] + (let [step (fn step [s] + (lazy-seq + (let [s (seq s)] + (when s + (let [fst (first s) + fv (f fst) + run (cons fst (take-while (fn [x] (= fv (f x))) (rest s)))] + (cons run (step (lazy-seq (drop (count run) s)))))))))] + (step coll))) diff --git a/jolt-core/clojure/core/20-coll.clj b/jolt-core/clojure/core/20-coll.clj index d1868fd..b0a5c95 100644 --- a/jolt-core/clojure/core/20-coll.clj +++ b/jolt-core/clojure/core/20-coll.clj @@ -208,16 +208,32 @@ ;; No ratio type on Jolt, so rationalize is identity. (defn rationalize [x] x) +;; trampoline: repeatedly calls f with args until a non-function result. +(defn trampoline + ([f] (trampoline f (f))) + ([f & args] + (let [ret (apply f args)] + (if (fn? ret) + (recur ret) + ret)))) + +;; rand-int: random integer in [0, n). Uses Janet math/random. +(defn rand-int [n] (math/floor (* (math/random) n))) + ;; Eager dedupe of consecutive equal elements (Jolt has no transducer arity yet). (defn dedupe [coll] - (let [c (vec coll)] - (if (empty? c) - [] - (loop [prev (first c) xs (rest c) out [(first c)]] - (if (seq xs) - (let [x (first xs)] - (recur x (rest xs) (if (= x prev) out (conj out x)))) - out))))) + (let [step (fn step [s prev] + (lazy-seq + (let [s (seq s)] + (when s + (let [x (first s)] + (if (= x prev) + (step (rest s) prev) + (cons x (step (rest s) x))))))))] + (let [s (seq coll)] + (if s + (cons (first s) (step (rest s) (first s))) + ())))) ;; Internal helper for {:keys [...]} destructuring over a seq of k/v pairs: ;; builds a map from consecutive pairs, dropping a trailing unpaired element. diff --git a/src/jolt/core.janet b/src/jolt/core.janet index 58fe11d..c81508e 100644 --- a/src/jolt/core.janet +++ b/src/jolt/core.janet @@ -244,7 +244,6 @@ (defn core-min [& args] (each x args (need-num x "min")) (apply min args)) (defn core-rand [] (math/random)) -(defn core-rand-int [n] (math/floor (* (math/random) n))) # ============================================================ # Comparison @@ -1318,21 +1317,6 @@ (+= i step)) result)))) -(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) (defn core-partition-all [n coll] (if (lazy-seq? coll) @@ -1419,10 +1403,6 @@ # subvec lives in the Clojure kernel tier — core/00-kernel.clj. -(defn core-trampoline [f & args] - (var result (apply f args)) - (while (function? result) (set result (result))) - result) (def core-format (fn [fmt & args] (string/format fmt ;args))) @@ -2818,7 +2798,6 @@ "max" core-max "min" core-min "rand" core-rand - "rand-int" core-rand-int "=" core-= "not=" core-not= "<" core-< @@ -2837,7 +2816,6 @@ "map-indexed" core-map-indexed "cycle" core-cycle "pop" core-pop - "trampoline" core-trampoline "format" core-format "first" core-first "rest" core-rest @@ -2958,7 +2936,6 @@ "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 diff --git a/test/integration/lazy-infinite-test.janet b/test/integration/lazy-infinite-test.janet index 982f305..b1233d3 100644 --- a/test/integration/lazy-infinite-test.janet +++ b/test/integration/lazy-infinite-test.janet @@ -55,6 +55,7 @@ ["take 6 mapcat dup range" "(quote (0 0 1 1 2 2))" "(take 6 (mapcat (fn [x] [x x]) (range)))"] ["first rest lazy" "1" "(let [[a & r] (range)] (first r))"] ["take 3 rest lazy" "(quote (1 2 3))" "(let [[a & r] (range)] (take 3 r))"] + ["dedupe inf" "(quote (1 2 1 2 1))" "(take 5 (dedupe (cycle [1 1 2 2])))"] ["take 3 take-nth 2 range" "(quote (0 2 4))" "(take 3 (take-nth 2 (range)))"] ["take 3 interpose :x range" "(quote (0 :x 1))" "(take 3 (interpose :x (range)))"] ["take 3 map vector range iterate" "(quote ([0 100] [1 101] [2 102]))" "(take 3 (map vector (range) (iterate inc 100)))"]