mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-10 22:31:32 +02:00
@@ -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)
|
||||||
|
@@ -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())
|
||||||
|
@@ -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
89
di/erasure/injector.go
Normal 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
167
di/erasure/provider.go
Normal 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
33
di/erasure/token.go
Normal 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
85
di/provider.go
Normal 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
38
di/provider_test.go
Normal 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
105
di/token.go
Normal 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),
|
||||||
|
}
|
||||||
|
}
|
@@ -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])
|
||||||
|
@@ -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)
|
||||||
}
|
}
|
||||||
|
@@ -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])
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user