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

fix: checkin

Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
Carsten Leue
2023-11-08 20:21:38 +01:00
parent 5b7e5b153b
commit 37430c0698
14 changed files with 576 additions and 7 deletions

View File

@@ -52,6 +52,10 @@ func MonadMapRef[A, B any](as []A, f func(a *A) B) []B {
return bs return bs
} }
func MapWithIndex[A, B any](f func(int, A) B) func([]A) []B {
return G.MapWithIndex[[]A, []B](f)
}
func Map[A, B any](f func(a A) B) func([]A) []B { func Map[A, B any](f func(a A) B) func([]A) []B {
return F.Bind2nd(MonadMap[A, B], f) return F.Bind2nd(MonadMap[A, B], f)
} }
@@ -300,6 +304,11 @@ func FoldMap[A, B any](m M.Monoid[B]) func(func(A) B) func([]A) B {
return G.FoldMap[[]A](m) return G.FoldMap[[]A](m)
} }
// FoldMapWithIndex maps and folds an array. Map the Array passing each value to the iterating function. Then fold the results using the provided Monoid.
func FoldMapWithIndex[A, B any](m M.Monoid[B]) func(func(int, A) B) func([]A) B {
return G.FoldMapWithIndex[[]A](m)
}
// Fold folds the array using the provided Monoid. // Fold folds the array using the provided Monoid.
func Fold[A any](m M.Monoid[A]) func([]A) A { func Fold[A any](m M.Monoid[A]) func([]A) A {
return G.Fold[[]A](m) return G.Fold[[]A](m)

View File

@@ -118,6 +118,14 @@ func Map[GA ~[]A, GB ~[]B, A, B any](f func(a A) B) func(GA) GB {
return F.Bind2nd(MonadMap[GA, GB, A, B], f) return F.Bind2nd(MonadMap[GA, GB, A, B], f)
} }
func MonadMapWithIndex[GA ~[]A, GB ~[]B, A, B any](as GA, f func(int, A) B) GB {
return array.MonadMapWithIndex[GA, GB](as, f)
}
func MapWithIndex[GA ~[]A, GB ~[]B, A, B any](f func(int, A) B) func(GA) GB {
return F.Bind2nd(MonadMapWithIndex[GA, GB, A, B], f)
}
func Size[GA ~[]A, A any](as GA) int { func Size[GA ~[]A, A any](as GA) int {
return len(as) return len(as)
} }
@@ -242,6 +250,16 @@ func FoldMap[AS ~[]A, A, B any](m M.Monoid[B]) func(func(A) B) func(AS) B {
} }
} }
func FoldMapWithIndex[AS ~[]A, A, B any](m M.Monoid[B]) func(func(int, A) B) func(AS) B {
return func(f func(int, A) B) func(AS) B {
return func(as AS) B {
return array.ReduceWithIndex(as, func(idx int, cur B, a A) B {
return m.Concat(cur, f(idx, a))
}, m.Empty())
}
}
}
func Fold[AS ~[]A, A any](m M.Monoid[A]) func(AS) A { func Fold[AS ~[]A, A any](m M.Monoid[A]) func(AS) A {
return func(as AS) A { return func(as AS) A {
return array.Reduce(as, m.Concat, m.Empty()) return array.Reduce(as, m.Concat, m.Empty())

View File

@@ -18,6 +18,7 @@ package array
import ( import (
"github.com/IBM/fp-go/internal/array" "github.com/IBM/fp-go/internal/array"
M "github.com/IBM/fp-go/monoid" M "github.com/IBM/fp-go/monoid"
S "github.com/IBM/fp-go/semigroup"
) )
func concat[T any](left, right []T) []T { func concat[T any](left, right []T) []T {
@@ -40,6 +41,10 @@ func Monoid[T any]() M.Monoid[[]T] {
return M.MakeMonoid(concat[T], Empty[T]()) return M.MakeMonoid(concat[T], Empty[T]())
} }
func Semigroup[T any]() S.Semigroup[[]T] {
return S.MakeSemigroup(concat[T])
}
func addLen[A any](count int, data []A) int { func addLen[A any](count int, data []A) int {
return count + len(data) return count + len(data)
} }

89
di/erasure/injector.go Normal file
View File

@@ -0,0 +1,89 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package erasure
import (
"fmt"
A "github.com/IBM/fp-go/array"
F "github.com/IBM/fp-go/function"
I "github.com/IBM/fp-go/identity"
IOE "github.com/IBM/fp-go/ioeither"
O "github.com/IBM/fp-go/option"
R "github.com/IBM/fp-go/record"
T "github.com/IBM/fp-go/tuple"
)
func providerToEntry(p Provider) T.Tuple2[string, ProviderFactory] {
return T.MakeTuple2(p.Provides().Id(), p.Factory())
}
func missingProviderError(name string) func() IOE.IOEither[error, any] {
return func() IOE.IOEither[error, any] {
return IOE.Left[any](fmt.Errorf("No provider for dependency [%s]", name))
}
}
func MakeInjector(providers []Provider) InjectableFactory {
type Result = IOE.IOEither[error, any]
// provide a mapping for all providers
factoryById := F.Pipe2(
providers,
A.Map(providerToEntry),
R.FromEntries[string, ProviderFactory],
)
// the resolved map
var resolved = R.Empty[string, Result]()
// the callback
var injFct InjectableFactory
// lazy initialization, so we can cross reference it
injFct = func(token Token) Result {
hit := F.Pipe3(
token,
Token.Id,
R.Lookup[Result, string],
I.Ap[O.Option[Result]](resolved),
)
provFct := F.Pipe2(
token,
T.Replicate2[Token],
T.Map2(F.Flow3(
Token.Id,
R.Lookup[ProviderFactory, string],
I.Ap[O.Option[ProviderFactory]](factoryById),
), F.Flow2(
Token.String,
missingProviderError,
)),
)
x := F.Pipe4(
token,
Token.Id,
R.Lookup[Result, string],
I.Ap[O.Option[Result]](resolved),
O.GetOrElse(F.Flow2()),
)
}
return injFct
}

167
di/erasure/provider.go Normal file
View File

@@ -0,0 +1,167 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package erasure
import (
"fmt"
A "github.com/IBM/fp-go/array"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
IO "github.com/IBM/fp-go/io"
IOG "github.com/IBM/fp-go/io/generic"
IOE "github.com/IBM/fp-go/ioeither"
O "github.com/IBM/fp-go/option"
RIOE "github.com/IBM/fp-go/readerioeither"
R "github.com/IBM/fp-go/record"
T "github.com/IBM/fp-go/tuple"
)
type InjectableFactory = RIOE.ReaderIOEither[Token, error, any]
type ProviderFactory = RIOE.ReaderIOEither[InjectableFactory, error, any]
type Provider interface {
fmt.Stringer
Provides() Token
Factory() ProviderFactory
}
type provider struct {
provides Token
factory ProviderFactory
}
func (p *provider) Provides() Token {
return p.provides
}
func (p *provider) Factory() ProviderFactory {
return p.factory
}
func (p *provider) String() string {
return fmt.Sprintf("Provider for [%s]", p.provides)
}
func MakeProvider(token Token, fct ProviderFactory) Provider {
return &provider{token, fct}
}
func mapFromToken(idx int, token Token) map[TokenType]map[int]int {
return R.Singleton(token.Type(), R.Singleton(idx, idx))
}
var mergeTokenMaps = R.UnionMonoid[TokenType](R.UnionLastSemigroup[int, int]())
var foldDeps = A.FoldMapWithIndex[Token](mergeTokenMaps)(mapFromToken)
var lookupMandatory = R.Lookup[map[int]int](Mandatory)
var lookupOption = R.Lookup[map[int]int](Option)
type Mapping = map[TokenType]map[int]int
func getAt[T any](ar []T) func(idx int) T {
return func(idx int) T {
return ar[idx]
}
}
func handleMandatory(mp Mapping) func(res []IOE.IOEither[error, any]) IOE.IOEither[error, map[int]any] {
onNone := F.Nullary2(R.Empty[int, any], IOE.Of[error, map[int]any])
return func(res []IOE.IOEither[error, any]) IOE.IOEither[error, map[int]any] {
return F.Pipe2(
mp,
lookupMandatory,
O.Fold(
onNone,
IOE.TraverseRecord[int](getAt(res)),
),
)
}
}
func handleOption(mp Mapping) func(res []IOE.IOEither[error, any]) IO.IO[map[int]O.Option[any]] {
onNone := F.Nullary2(R.Empty[int, O.Option[any]], IO.Of[map[int]O.Option[any]])
return func(res []IOE.IOEither[error, any]) IO.IO[map[int]O.Option[any]] {
return F.Pipe2(
mp,
lookupOption,
O.Fold(
onNone,
F.Flow2(
IOG.TraverseRecord[IO.IO[map[int]E.Either[error, any]], map[int]int](getAt(res)),
IO.Map(R.Map[int](E.ToOption[error, any])),
),
),
)
}
}
func mergeArguments(count int) func(
mandatory IOE.IOEither[error, map[int]any],
optonal IO.IO[map[int]O.Option[any]],
) IOE.IOEither[error, []any] {
optMapToAny := R.Map[int](F.ToAny[O.Option[any]])
mergeMaps := R.UnionLastMonoid[int, any]()
return func(
mandatory IOE.IOEither[error, map[int]any],
optional IO.IO[map[int]O.Option[any]],
) IOE.IOEither[error, []any] {
return F.Pipe1(
IOE.SequenceT2(mandatory, IOE.FromIO[error](optional)),
IOE.Map[error](T.Tupled2(func(mnd map[int]any, opt map[int]O.Option[any]) []any {
// merge all parameters
merged := mergeMaps.Concat(mnd, optMapToAny(opt))
return R.ReduceWithIndex(func(idx int, res []any, value any) []any {
res[idx] = value
return res
}, make([]any, count))(merged)
})),
)
}
}
func MakeProviderFactory(
deps []Token,
fct func(param ...any) IOE.IOEither[error, any]) ProviderFactory {
mapping := foldDeps(deps)
mandatory := handleMandatory(mapping)
optional := handleOption(mapping)
merge := mergeArguments(A.Size(deps))
f := F.Unvariadic0(fct)
return func(inj InjectableFactory) IOE.IOEither[error, any] {
// resolve all dependencies
resolved := A.MonadMap(deps, inj)
// resolve dependencies
return F.Pipe1(
merge(mandatory(resolved), optional(resolved)),
IOE.Chain(f),
)
}
}

33
di/erasure/token.go Normal file
View File

@@ -0,0 +1,33 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package erasure
import "fmt"
type TokenType int
const (
Mandatory TokenType = iota
Option
IOEither
IOOption
)
type Token interface {
fmt.Stringer
Id() string
Type() TokenType
}

85
di/provider.go Normal file
View File

@@ -0,0 +1,85 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package di
import (
A "github.com/IBM/fp-go/array"
DIE "github.com/IBM/fp-go/di/erasure"
E "github.com/IBM/fp-go/either"
ER "github.com/IBM/fp-go/erasure"
"github.com/IBM/fp-go/errors"
F "github.com/IBM/fp-go/function"
IOE "github.com/IBM/fp-go/ioeither"
T "github.com/IBM/fp-go/tuple"
)
func lookupAt[T any](idx int) func(params []any) E.Either[error, T] {
return F.Flow3(
A.Lookup[any](idx),
E.FromOption[any](errors.OnNone("No parameter at position %d", idx)),
E.Chain(ER.SafeUnerase[T]),
)
}
func eraseProviderFactory0[R any](f func() IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {
return func(params ...any) IOE.IOEither[error, any] {
return F.Pipe1(
f(),
IOE.Map[error](ER.Erase[R]),
)
}
}
func eraseProviderFactory1[T1 any, R any](
f func(T1) IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {
ft := T.Tupled1(f)
t1 := lookupAt[T1](0)
return func(params ...any) IOE.IOEither[error, any] {
return F.Pipe3(
E.SequenceT1(t1(params)),
IOE.FromEither[error, T.Tuple1[T1]],
IOE.Chain(ft),
IOE.Map[error](ER.Erase[R]),
)
}
}
func MakeProvider0[R any](
token InjectionToken[R],
fct func() IOE.IOEither[error, R],
) DIE.Provider {
return DIE.MakeProvider(
token,
DIE.MakeProviderFactory(
A.Empty[DIE.Token](),
eraseProviderFactory0(fct),
),
)
}
func MakeProvider1[T1, R any](
token InjectionToken[R],
d1 InjectionToken[T1],
fct func(T1) IOE.IOEither[error, R],
) DIE.Provider {
return DIE.MakeProvider(
token,
DIE.MakeProviderFactory(
A.From[DIE.Token](d1),
eraseProviderFactory1(fct),
),
)
}

38
di/provider_test.go Normal file
View File

@@ -0,0 +1,38 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package di
import (
"fmt"
"testing"
F "github.com/IBM/fp-go/function"
IOE "github.com/IBM/fp-go/ioeither"
)
func staticValue(value string) func() IOE.IOEither[error, string] {
return F.Constant(IOE.Of[error](value))
}
var (
INJ_KEY1 = MakeToken[string]("INJ_KEY1")
INJ_KEY2 = MakeToken[string]("INJ_KEY2")
)
func TestSimpleProvider(t *testing.T) {
p1 := MakeProvider0(INJ_KEY1, staticValue("Carsten"))
fmt.Println(p1)
}

105
di/token.go Normal file
View File

@@ -0,0 +1,105 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package di
import (
"fmt"
"strconv"
"sync/atomic"
DIE "github.com/IBM/fp-go/di/erasure"
IO "github.com/IBM/fp-go/io"
IOE "github.com/IBM/fp-go/ioeither"
IOO "github.com/IBM/fp-go/iooption"
O "github.com/IBM/fp-go/option"
)
type Token[T any] interface {
DIE.Token
ToType(any) O.Option[T]
}
type InjectionToken[T any] interface {
Token[T]
Option() Token[O.Option[T]]
IOEither() Token[IOE.IOEither[error, T]]
IOOption() Token[IOO.IOOption[T]]
}
func makeId() IO.IO[string] {
var count int64
return func() string {
return strconv.FormatInt(atomic.AddInt64(&count, 1), 16)
}
}
var genId = makeId()
type token[T any] struct {
name string
id string
typ DIE.TokenType
}
func (t *token[T]) Id() string {
return t.id
}
func (t *token[T]) Type() DIE.TokenType {
return t.typ
}
func (t *token[T]) ToType(value any) O.Option[T] {
return O.ToType[T](value)
}
func (t *token[T]) String() string {
return t.name
}
func makeToken[T any](name string, id string, typ DIE.TokenType) Token[T] {
return &token[T]{name, id, typ}
}
type injectionToken[T any] struct {
token[T]
option Token[O.Option[T]]
ioeither Token[IOE.IOEither[error, T]]
iooption Token[IOO.IOOption[T]]
}
func (i *injectionToken[T]) Option() Token[O.Option[T]] {
return i.option
}
func (i *injectionToken[T]) IOEither() Token[IOE.IOEither[error, T]] {
return i.ioeither
}
func (i *injectionToken[T]) IOOption() Token[IOO.IOOption[T]] {
return i.iooption
}
// MakeToken create a unique injection token for a specific type
func MakeToken[T any](name string) InjectionToken[T] {
id := genId()
return &injectionToken[T]{
token[T]{name, id, DIE.Mandatory},
makeToken[O.Option[T]](fmt.Sprintf("Option[%s]", name), id, DIE.Option),
makeToken[IOE.IOEither[error, T]](fmt.Sprintf("IOEither[%s]", name), id, DIE.IOEither),
makeToken[IOO.IOOption[T]](fmt.Sprintf("IOOption[%s]", name), id, DIE.IOOption),
}
}

View File

@@ -16,6 +16,8 @@
package erasure package erasure
import ( import (
E "github.com/IBM/fp-go/either"
"github.com/IBM/fp-go/errors"
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
) )
@@ -29,6 +31,15 @@ func Unerase[T any](t any) T {
return *t.(*T) return *t.(*T)
} }
// SafeUnerase converts an erased variable back to its original value
func SafeUnerase[T any](t any) E.Either[error, T] {
return F.Pipe2(
t,
E.ToType[*T](errors.OnSome[any]("Value %T is not unerased")),
E.Map[error](F.Deref[T]),
)
}
// Erase0 converts a type safe function into an erased function // Erase0 converts a type safe function into an erased function
func Erase0[T1 any](f func() T1) func() any { func Erase0[T1 any](f func() T1) func() any {
return F.Nullary2(f, Erase[T1]) return F.Nullary2(f, Erase[T1])

View File

@@ -88,6 +88,15 @@ func MonadMap[GA ~[]A, GB ~[]B, A, B any](as GA, f func(a A) B) GB {
return bs return bs
} }
func MonadMapWithIndex[GA ~[]A, GB ~[]B, A, B any](as GA, f func(idx int, a A) B) GB {
count := len(as)
bs := make(GB, count)
for i := count - 1; i >= 0; i-- {
bs[i] = f(i, as[i])
}
return bs
}
func ConstNil[GA ~[]A, A any]() GA { func ConstNil[GA ~[]A, A any]() GA {
return (GA)(nil) return (GA)(nil)
} }

View File

@@ -57,7 +57,7 @@ func SequenceArray[GA ~func() A, GAS ~func() AAS, AAS ~[]A, GAAS ~[]GA, A any](t
} }
// MonadTraverseRecord transforms a record using an IO transform an IO of a record // MonadTraverseRecord transforms a record using an IO transform an IO of a record
func MonadTraverseRecord[GB ~func() B, GBS ~func() MB, MA ~map[K]A, MB ~map[K]B, K comparable, A, B any](ma MA, f func(A) GB) GBS { func MonadTraverseRecord[GBS ~func() MB, MA ~map[K]A, GB ~func() B, MB ~map[K]B, K comparable, A, B any](ma MA, f func(A) GB) GBS {
return RR.MonadTraverse[MA]( return RR.MonadTraverse[MA](
Of[GBS, MB], Of[GBS, MB],
Map[GBS, func() func(B) MB, MB, func(B) MB], Map[GBS, func() func(B) MB, MB, func(B) MB],
@@ -67,7 +67,7 @@ func MonadTraverseRecord[GB ~func() B, GBS ~func() MB, MA ~map[K]A, MB ~map[K]B,
} }
// TraverseRecord transforms a record using an IO transform an IO of a record // TraverseRecord transforms a record using an IO transform an IO of a record
func TraverseRecord[GB ~func() B, GBS ~func() MB, MA ~map[K]A, MB ~map[K]B, K comparable, A, B any](f func(A) GB) func(MA) GBS { func TraverseRecord[GBS ~func() MB, MA ~map[K]A, GB ~func() B, MB ~map[K]B, K comparable, A, B any](f func(A) GB) func(MA) GBS {
return RR.Traverse[MA]( return RR.Traverse[MA](
Of[GBS, MB], Of[GBS, MB],
Map[GBS, func() func(B) MB, MB, func(B) MB], Map[GBS, func() func(B) MB, MB, func(B) MB],
@@ -87,5 +87,5 @@ func TraverseRecordWithIndex[GB ~func() B, GBS ~func() MB, MA ~map[K]A, MB ~map[
} }
func SequenceRecord[GA ~func() A, GAS ~func() AAS, AAS ~map[K]A, GAAS ~map[K]GA, K comparable, A any](tas GAAS) GAS { func SequenceRecord[GA ~func() A, GAS ~func() AAS, AAS ~map[K]A, GAAS ~map[K]GA, K comparable, A any](tas GAAS) GAS {
return MonadTraverseRecord[GA, GAS](tas, F.Identity[GA]) return MonadTraverseRecord[GAS](tas, F.Identity[GA])
} }

View File

@@ -41,13 +41,13 @@ func SequenceArray[A any](tas []IO[A]) IO[[]A] {
} }
func MonadTraverseRecord[K comparable, A, B any](tas map[K]A, f func(A) IO[B]) IO[map[K]B] { func MonadTraverseRecord[K comparable, A, B any](tas map[K]A, f func(A) IO[B]) IO[map[K]B] {
return G.MonadTraverseRecord[IO[B], IO[map[K]B]](tas, f) return G.MonadTraverseRecord[IO[map[K]B]](tas, f)
} }
// TraverseRecord applies a function returning an [IO] to all elements in a record and the // TraverseRecord applies a function returning an [IO] to all elements in a record and the
// transforms this into an [IO] of that record // transforms this into an [IO] of that record
func TraverseRecord[K comparable, A, B any](f func(A) IO[B]) func(map[K]A) IO[map[K]B] { func TraverseRecord[K comparable, A, B any](f func(A) IO[B]) func(map[K]A) IO[map[K]B] {
return G.TraverseRecord[IO[B], IO[map[K]B], map[K]A](f) return G.TraverseRecord[IO[map[K]B], map[K]A, IO[B]](f)
} }
// TraverseRecordWithIndex applies a function returning an [IO] to all elements in a record and the // TraverseRecordWithIndex applies a function returning an [IO] to all elements in a record and the

View File

@@ -41,13 +41,13 @@ func SequenceArray[A any](tas []Lazy[A]) Lazy[[]A] {
} }
func MonadTraverseRecord[K comparable, A, B any](tas map[K]A, f func(A) Lazy[B]) Lazy[map[K]B] { func MonadTraverseRecord[K comparable, A, B any](tas map[K]A, f func(A) Lazy[B]) Lazy[map[K]B] {
return G.MonadTraverseRecord[Lazy[B], Lazy[map[K]B]](tas, f) return G.MonadTraverseRecord[Lazy[map[K]B]](tas, f)
} }
// TraverseRecord applies a function returning an [IO] to all elements in a record and the // TraverseRecord applies a function returning an [IO] to all elements in a record and the
// transforms this into an [IO] of that record // transforms this into an [IO] of that record
func TraverseRecord[K comparable, A, B any](f func(A) Lazy[B]) func(map[K]A) Lazy[map[K]B] { func TraverseRecord[K comparable, A, B any](f func(A) Lazy[B]) func(map[K]A) Lazy[map[K]B] {
return G.TraverseRecord[Lazy[B], Lazy[map[K]B], map[K]A](f) return G.TraverseRecord[Lazy[map[K]B], map[K]A, Lazy[B]](f)
} }
// TraverseRecord applies a function returning an [IO] to all elements in a record and the // TraverseRecord applies a function returning an [IO] to all elements in a record and the