Skip to content

Commit

Permalink
Adding reductions (#421)
Browse files Browse the repository at this point in the history
* Port `clojure.core/reductions`

* Fixes #418

* Add tests for reductions

* Add test that you can compose with reductions

* Update changelog
  • Loading branch information
PEZ authored Dec 7, 2023
1 parent 1200c3e commit 5fcd525
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- Fix `reduce` without initial value + empty coll, it should call `f()`
- Add serve-playground bb task
- Update playground with button for creating a blank AOC playground
- [#418](): Add `reductions`

## 0.4.73 (2023-12-05)

Expand Down
1 change: 1 addition & 0 deletions resources/squint/core.edn
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@
reduce_kv
reduced
reduced_QMARK_
reductions
regexp_QMARK_
remove
remove_watch
Expand Down
26 changes: 26 additions & 0 deletions src/squint/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,32 @@ export function reduce(f, arg1, arg2) {
return val;
}

function _reductions(f, arg1, arg2) {
const [init, coll] = arg2 === undefined ? [undefined, arg1]: [arg1, arg2];
const s = seq(coll);
if (init === undefined) {
// (reductions f coll)
return new LazySeq(function () {
return s ? _reductions(f, first(s), rest(s)) : list(f());
});
} else {
// (reductions f val coll)
if (reduced_QMARK_(init)) {
return list(init.value);
}
return cons(init, new LazySeq(function () {
if (s) {
return _reductions(f, f(init, first(s)), rest(s));
}
}));
}
}

export function reductions(f, arg1, arg2) {
f = toFn(f);
return _reductions(f, arg1, arg2);
}

var tolr = false;
export function warn_on_lazy_reusage_BANG_() {
tolr = true;
Expand Down
76 changes: 76 additions & 0 deletions test/squint/compiler_test.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,82 @@
(is (jsv! '(reduced? (reduced 5))))
(is (= 4 (jsv! '(deref (reduced 4))))))

(deftest reductions-test
(testing "lazy"
(is (eq (vec (take 10 (reductions + (range))))
(jsv! `(vec (take 10 (reductions + (range))))))
"Returns a lazy sequence"))
(testing "no val"
(is (eq (vec (reductions + [1 1 1 1])) (jsv! '(vec (reductions + [1 1 1 1])))))
(is (eq (vec (reductions #(if (< %2 3)
(+ %1 %2)
(reduced %1))
(range 5)))
(jsv! '(vec (reductions #(if (< %2 3)
(+ %1 %2)
(reduced %1))
(range 5)))))
"reduced early")
(is (eq (reduce #(if (< %2 4)
(+ %1 %2)
(reduced %1))
(range 5))
(jsv! '(reduce #(if (< %2 4)
(+ %1 %2)
(reduced %1))
(range 5))))
"reduced last el")
(is (eq (vec (reductions (fn [x _] (reduced x))
(range 5)))
(jsv! '(vec (reductions (fn [x _] (reduced x))
(range 5)))))
"reduced first el"))
(testing "val"
(is (eq (vec (reductions conj [] '(1 2 3)))
(jsv! '(vec (reductions conj [] '(1 2 3)))))))
(testing "sets"
(is (eq (vec (reductions #(+ %1 %2) #{1 2 3 4}))
(jsv! '(vec (reductions #(+ %1 %2) #{1 2 3 4}))))))
(testing "maps"
(is (eq (vec (reductions #(+ %1 (second %2))
0
{:a 1, :b 2, :c 3, :d 4}))
(jsv! '(vec (reductions #(+ %1 (second %2))
0
(js/Map. [[:a 1] [:b 2] [:c 3] [:d 4]])))))))
(testing "objects"
(is (eq (vec (reductions #(+ %1 (second %2))
0
{:a 1, :b 2, :c 3, :d 4}))
(jsv! '(vec (reductions #(+ %1 (second %2))
0
(js/Object.entries {:a 1, :b 2, :c 3, :d 4}))))))
(is (eq (vec (reductions #(+ %1 %2)
0
(vals {:a 1 :b 2 :c 3 :d 4})))
(jsv! '(vec (reductions #(+ %1 %2)
0
(js/Object.values {:a 1 :b 2 :c 3 :d 4}))))))
(is (eq (vec (reductions #(+ %1 (second %2))
0
{:a 1, :b 2, :c 3, :d 4}))
(jsv! '(vec (reductions #(+ %1 (second %2))
0
{:a 1 :b 2 :c 3 :d 4}))))))
(testing "empty coll"
(is (eq (vec (reductions + '())) (jsv! '(vec (reductions + '())))))
(is (eq (vec (reductions + [])) (jsv! '(vec (reductions + []))))))
(testing "composability"
;; https://clojuredocs.org/clojure.core/reductions#example-58bdd686e4b01f4add58fe6b
(is (eq (vec (take 3 (as-> (repeat {:height 50}) posts
(map #(assoc %1 :offset %2)
posts
(reductions + 0 (map :height posts))))))
(jsv! '(vec (take 3 (as-> (repeat {:height 50}) posts
(map #(assoc %1 :offset %2)
posts
(reductions + 0 (map :height posts)))))))))))

(deftest seq-test
(is (= "abc" (jsv! '(seq "abc"))))
(is (eq '(1 2 3) (jsv! '(seq [1 2 3]))))
Expand Down

0 comments on commit 5fcd525

Please sign in to comment.