Skip to content

Commit 27f7d01

Browse files
authored
Support reducing Records by reduce-kv (#1114)
Fix #1102
1 parent c0fc7ea commit 27f7d01

File tree

3 files changed

+46
-7
lines changed

3 files changed

+46
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010

1111
### Fixed
1212
* Fix a bug where symbols and keyword containing `:` characters in the name were rejected by the reader (#1105)
13+
* Fix a bug where records did not support reducing via `reduce-kv` (#1102)
1314

1415
## [v0.3.0]
1516
### Added

src/basilisp/core.lpy

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6842,12 +6842,12 @@
68426842
in the body of a method should not include that parameter, as it will be supplied
68436843
automatically."
68446844
[type-name fields & method-impls]
6845-
(let [ctor-name (with-meta
6846-
(symbol (str "->" (name type-name)))
6847-
(meta type-name))
6848-
map-ctor (with-meta
6849-
(symbol (str "map->" (name type-name)))
6850-
(meta type-name))
6845+
(let [ctor-name (with-meta
6846+
(symbol (str "->" (name type-name)))
6847+
(meta type-name))
6848+
map-ctor (with-meta
6849+
(symbol (str "map->" (name type-name)))
6850+
(meta type-name))
68516851

68526852
record-fields (vec (concat fields
68536853
['^{:default nil} meta
@@ -6861,6 +6861,7 @@
68616861
'[basilisp.lang.interfaces/IPersistentMap
68626862
basilisp.lang.interfaces/IWithMeta
68636863
basilisp.lang.interfaces/IRecord
6864+
basilisp.lang.interfaces/IReduceKV
68646865
python/object])
68656866

68666867
;; We can use these gensyms repeatedly and interpolate them in
@@ -7005,6 +7006,17 @@
70057006
(str "#" ~(name *ns*) "." qual-name))
70067007
print-meta (str "^" (repr (meta ~this-gs)) " "))))
70077008

7009+
;; IReduceKV
7010+
(~'reduce-kv [~this-gs f# init#]
7011+
(loop [res# init#
7012+
fields# (seq ~this-gs)]
7013+
(cond
7014+
(reduced? res#) (deref res#)
7015+
(seq fields#) (let [[k# v#] (first fields#)]
7016+
(recur (f# res# k# v#)
7017+
(rest fields#)))
7018+
:else res#)))
7019+
70087020
;; object
70097021
(~'__eq__ [~this-gs ~other-gs]
70107022
(or (identical? ~this-gs ~other-gs)

tests/basilisp/test_core_fns.lpy

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,8 @@
833833
(is (= 6 (reduce (f) (range))))
834834
(is (= 9 (reduce (f) 6 (range)))))))
835835

836+
(defrecord ReduceKVRecord [a b c])
837+
836838
(deftest reduce-kv-test
837839
(testing "reduce-kv does not execute f if no elems in coll"
838840
(let [a (atom false)]
@@ -864,7 +866,31 @@
864866
(update :ks conj i)
865867
(update :vs conj v)))
866868
{:ks [] :vs []}
867-
[:a :b :c])))))
869+
[:a :b :c]))))
870+
871+
(testing "works on records"
872+
(is (= :reduced (reduce-kv (fn [acc k v]
873+
(reduced :reduced))
874+
{:ks #{} :vs #{}}
875+
(->ReduceKVRecord 1 2 3))))
876+
877+
(let [rec (reduce-kv
878+
(fn [acc k v]
879+
(assoc acc k v))
880+
(->ReduceKVRecord 0 1 2)
881+
{:d 4 :e 5})]
882+
(is (record? rec))
883+
(is (instance? ReduceKVRecord rec)))
884+
885+
(are [res input] (= res (reduce-kv
886+
(fn [acc k v]
887+
(-> acc
888+
(update :ks conj k)
889+
(update :vs conj v)))
890+
{:ks #{} :vs #{}}
891+
input))
892+
{:ks #{:a :b :c} :vs #{1 2 3}} (->ReduceKVRecord 1 2 3)
893+
{:ks #{:a :b :c :d :e} :vs #{1 2 3 4 5}} (assoc (->ReduceKVRecord 1 2 3) :d 4 :e 5))))
868894

869895
(deftest fnil-test
870896
(let [f (fnil (fn [x] x) :yes)]

0 commit comments

Comments
 (0)