1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-08-10 22:31:32 +02:00

fix: implement foldMap for records

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
Dr. Carsten Leue
2024-01-12 17:19:38 +01:00
parent e7428549e4
commit 9ed9f8a171
3 changed files with 125 additions and 2 deletions

View File

@@ -19,6 +19,7 @@ import (
"sort" "sort"
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
RAG "github.com/IBM/fp-go/internal/array"
FC "github.com/IBM/fp-go/internal/functor" FC "github.com/IBM/fp-go/internal/functor"
G "github.com/IBM/fp-go/internal/record" G "github.com/IBM/fp-go/internal/record"
Mg "github.com/IBM/fp-go/magma" Mg "github.com/IBM/fp-go/magma"
@@ -334,6 +335,62 @@ func ToEntries[M ~map[K]V, GT ~[]T.Tuple2[K, V], K comparable, V any](r M) GT {
return ToArray[M, GT](r) return ToArray[M, GT](r)
} }
// FromFoldableMap uses the reduce method for a higher kinded type to transform
// its values into a tuple. The key and value are then used to populate the map. Duplicate
// values are resolved via the provided [Mg.Magma]
func FromFoldableMap[
FCT ~func(A) T.Tuple2[K, V],
HKTA any,
FOLDABLE ~func(func(M, A) M, M) func(HKTA) M,
M ~map[K]V,
A any,
K comparable,
V any](m Mg.Magma[V], fld FOLDABLE) func(f FCT) func(fa HKTA) M {
return func(f FCT) func(fa HKTA) M {
return fld(func(dst M, a A) M {
if IsEmpty(dst) {
dst = make(M)
}
e := f(a)
k := T.First(e)
old, ok := dst[k]
if ok {
dst[k] = m.Concat(old, T.Second(e))
} else {
dst[k] = T.Second(e)
}
return dst
}, Empty[M]())
}
}
func FromFoldable[
HKTA any,
FOLDABLE ~func(func(M, T.Tuple2[K, V]) M, M) func(HKTA) M,
M ~map[K]V,
K comparable,
V any](m Mg.Magma[V], red FOLDABLE) func(fa HKTA) M {
return FromFoldableMap[func(T.Tuple2[K, V]) T.Tuple2[K, V], HKTA, FOLDABLE](m, red)(F.Identity[T.Tuple2[K, V]])
}
func FromArrayMap[
FCT ~func(A) T.Tuple2[K, V],
GA ~[]A,
M ~map[K]V,
A any,
K comparable,
V any](m Mg.Magma[V]) func(f FCT) func(fa GA) M {
return FromFoldableMap[FCT](m, F.Bind23of3(RAG.Reduce[GA, A, M]))
}
func FromArray[
GA ~[]T.Tuple2[K, V],
M ~map[K]V,
K comparable,
V any](m Mg.Magma[V]) func(fa GA) M {
return FromFoldable[GA](m, F.Bind23of3(RAG.Reduce[GA, T.Tuple2[K, V], M]))
}
func FromEntries[M ~map[K]V, GT ~[]T.Tuple2[K, V], K comparable, V any](fa GT) M { func FromEntries[M ~map[K]V, GT ~[]T.Tuple2[K, V], K comparable, V any](fa GT) M {
m := make(M) m := make(M)
for _, t := range fa { for _, t := range fa {

View File

@@ -16,6 +16,7 @@
package record package record
import ( import (
EM "github.com/IBM/fp-go/endomorphism"
Mg "github.com/IBM/fp-go/magma" Mg "github.com/IBM/fp-go/magma"
Mo "github.com/IBM/fp-go/monoid" Mo "github.com/IBM/fp-go/monoid"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
@@ -291,6 +292,44 @@ func Copy[K comparable, V any](m map[K]V) map[K]V {
} }
// Clone creates a deep copy of the map using the provided endomorphism to clone the values // Clone creates a deep copy of the map using the provided endomorphism to clone the values
func Clone[K comparable, V any](f func(V) V) func(m map[K]V) map[K]V { func Clone[K comparable, V any](f EM.Endomorphism[V]) EM.Endomorphism[map[K]V] {
return G.Clone[map[K]V](f) return G.Clone[map[K]V](f)
} }
// FromFoldableMap converts from a reducer to a map
// Duplicate keys are resolved by the provided [Mg.Magma]
func FromFoldableMap[
FOLDABLE ~func(func(map[K]V, A) map[K]V, map[K]V) func(HKTA) map[K]V, // the reduce function
A any,
HKTA any,
K comparable,
V any](m Mg.Magma[V], red FOLDABLE) func(f func(A) T.Tuple2[K, V]) func(fa HKTA) map[K]V {
return G.FromFoldableMap[func(A) T.Tuple2[K, V]](m, red)
}
// FromArrayMap converts from an array to a map
// Duplicate keys are resolved by the provided [Mg.Magma]
func FromArrayMap[
A any,
K comparable,
V any](m Mg.Magma[V]) func(f func(A) T.Tuple2[K, V]) func(fa []A) map[K]V {
return G.FromArrayMap[func(A) T.Tuple2[K, V], []A, map[K]V](m)
}
// FromFoldable converts from a reducer to a map
// Duplicate keys are resolved by the provided [Mg.Magma]
func FromFoldable[
HKTA any,
FOLDABLE ~func(func(map[K]V, T.Tuple2[K, V]) map[K]V, map[K]V) func(HKTA) map[K]V, // the reduce function
K comparable,
V any](m Mg.Magma[V], red FOLDABLE) func(fa HKTA) map[K]V {
return G.FromFoldable[HKTA, FOLDABLE](m, red)
}
// FromArray converts from an array to a map
// Duplicate keys are resolved by the provided [Mg.Magma]
func FromArray[
K comparable,
V any](m Mg.Magma[V]) func(fa []T.Tuple2[K, V]) map[K]V {
return G.FromArray[[]T.Tuple2[K, V], map[K]V](m)
}

View File

@@ -1,5 +1,5 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved. // All rights reserved.
// Copyright (c) 2023 IBM Corp.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@@ -23,8 +23,10 @@ import (
A "github.com/IBM/fp-go/array" A "github.com/IBM/fp-go/array"
"github.com/IBM/fp-go/internal/utils" "github.com/IBM/fp-go/internal/utils"
Mg "github.com/IBM/fp-go/magma"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
S "github.com/IBM/fp-go/string" S "github.com/IBM/fp-go/string"
T "github.com/IBM/fp-go/tuple"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@@ -149,3 +151,28 @@ func TestCopyVsClone(t *testing.T) {
assert.NotEqual(t, cpy, cln) assert.NotEqual(t, cpy, cln)
assert.Equal(t, src, cpy) assert.Equal(t, src, cpy)
} }
func TestFromArrayMap(t *testing.T) {
src1 := A.From("a", "b", "c", "a")
frm := FromArrayMap[string, string](Mg.Second[string]())
f := frm(T.Replicate2[string])
res1 := f(src1)
assert.Equal(t, map[string]string{
"a": "a",
"b": "b",
"c": "c",
}, res1)
src2 := A.From("A", "B", "C", "A")
res2 := f(src2)
assert.Equal(t, map[string]string{
"A": "A",
"B": "B",
"C": "C",
}, res2)
}