Skip to content

Commit 04434d0

Browse files
authored
Fix MapKeySeq reduce operations (#125) (#136)
Implements IReduce and IReduceInit interfaces for MapKeySeq to fix "No method in multimethod 'coll-reduce' for dispatch value: *lang.MapKeySeq" error when using mapv on map keys. Changes: - Add Reduce and ReduceInit methods to MapKeySeq in pkg/lang/persistentarraymap.go - Add interface assertions for IReduce and IReduceInit compliance - Add comprehensive test cases in test/glojure/test_glojure/basic.glj Fixes issue where operations like (mapv identity (keys some-map)) would fail due to missing reduce implementation.
1 parent 6f3ed05 commit 04434d0

File tree

2 files changed

+56
-1
lines changed

2 files changed

+56
-1
lines changed

pkg/lang/persistentarraymap.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ var (
5151
_ IReduceInit = (*MapSeq)(nil)
5252
_ IDrop = (*MapSeq)(nil)
5353

54-
_ ASeq = (*MapKeySeq)(nil)
54+
_ ASeq = (*MapKeySeq)(nil)
55+
_ IReduce = (*MapKeySeq)(nil)
56+
_ IReduceInit = (*MapKeySeq)(nil)
5557

5658
_ ASeq = (*MapValSeq)(nil)
5759
_ IReduce = (*MapValSeq)(nil)
@@ -563,6 +565,39 @@ func (s *MapKeySeq) HashEq() uint32 {
563565
return aseqHashEq(&s.hasheq, s)
564566
}
565567

568+
func (s *MapKeySeq) Reduce(f IFn) any {
569+
count := 0
570+
var res any
571+
first := true
572+
for seq := Seq(s); seq != nil; seq = seq.Next() {
573+
count++
574+
if first {
575+
res = seq.First()
576+
first = false
577+
continue
578+
}
579+
res = f.Invoke(res, seq.First())
580+
if IsReduced(res) {
581+
return res.(IDeref).Deref()
582+
}
583+
}
584+
if count == 0 {
585+
return f.Invoke()
586+
}
587+
return res
588+
}
589+
590+
func (s *MapKeySeq) ReduceInit(f IFn, init any) any {
591+
res := init
592+
for seq := Seq(s); seq != nil; seq = seq.Next() {
593+
res = f.Invoke(res, seq.First())
594+
if IsReduced(res) {
595+
return res.(IDeref).Deref()
596+
}
597+
}
598+
return res
599+
}
600+
566601
////////////////////////////////////////////////////////////////////////////////
567602

568603
func NewMapValSeq(s ISeq) ISeq {

test/glojure/test_glojure/basic.glj

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,24 @@
108108
(is (:foo (meta ^:foo #{})))
109109
(is (:foo (meta ^:foo {}))))
110110

111+
(deftest map-key-seq-reduce
112+
(test-that "MapKeySeq implements reduce operations correctly"
113+
(let [test-map {:a 1 :b 2 :c 3 :d 4 :e 5}]
114+
;; Test mapv on keys (this was the original failing case)
115+
(is (= 5 (count (mapv identity (keys test-map)))))
116+
(is (vector? (mapv identity (keys test-map))))
117+
118+
;; Test reduce on keys
119+
(is (= 5 (reduce (fn [acc _] (inc acc)) 0 (keys test-map))))
120+
121+
;; Test mapv with transformation on keys
122+
(is (= 5 (count (mapv str (keys test-map)))))
123+
124+
;; Test that vals still work correctly
125+
(is (= 5 (count (mapv identity (vals test-map)))))
126+
(is (= 15 (reduce + (vals test-map))))
127+
128+
;; Test with namespace map keys (the original bug report case)
129+
(is (number? (count (mapv str (keys (ns-map *ns*)))))))))
130+
111131
(run-tests)

0 commit comments

Comments
 (0)