From a87de2f644a9823e356340b9322666d7b7c3be2e Mon Sep 17 00:00:00 2001 From: "Dr. Carsten Leue" Date: Mon, 18 Dec 2023 09:28:36 +0100 Subject: [PATCH] fix: use endomorphism in optics Signed-off-by: Dr. Carsten Leue --- di/erasure/provider.go | 42 ++++++++------- endomorphism/curry.go | 30 +++++++++++ endomorphism/generic/curry.go | 36 +++++++++++++ http/form/form.go | 3 +- ioeither/http/builder/builder.go | 26 +++------ optics/iso/iso.go | 7 +-- optics/iso/lens/lens.go | 5 +- optics/lens/lens.go | 92 ++++++++++++++++---------------- optics/optional/optional.go | 9 ++-- optics/prism/prism.go | 13 ++--- 10 files changed, 162 insertions(+), 101 deletions(-) create mode 100644 endomorphism/curry.go create mode 100644 endomorphism/generic/curry.go diff --git a/di/erasure/provider.go b/di/erasure/provider.go index 437fd34..1a07fa5 100644 --- a/di/erasure/provider.go +++ b/di/erasure/provider.go @@ -31,25 +31,28 @@ import ( R "github.com/IBM/fp-go/record" ) -type InjectableFactory = func(Dependency) IOE.IOEither[error, any] -type ProviderFactory = func(InjectableFactory) IOE.IOEither[error, any] +type ( + InjectableFactory = func(Dependency) IOE.IOEither[error, any] + ProviderFactory = func(InjectableFactory) IOE.IOEither[error, any] -type paramIndex = map[int]int -type paramValue = map[int]any -type handler = func(paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] + paramIndex = map[int]int + paramValue = map[int]any + handler = func(paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] + mapping = map[int]paramIndex -type Provider interface { - fmt.Stringer - // Provides returns the [Dependency] implemented by this provider - Provides() Dependency - // Factory returns s function that can create an instance of the dependency based on an [InjectableFactory] - Factory() ProviderFactory -} + Provider interface { + fmt.Stringer + // Provides returns the [Dependency] implemented by this provider + Provides() Dependency + // Factory returns s function that can create an instance of the dependency based on an [InjectableFactory] + Factory() ProviderFactory + } -type provider struct { - provides Dependency - factory ProviderFactory -} + provider struct { + provides Dependency + factory ProviderFactory + } +) func (p *provider) Provides() Dependency { return p.provides @@ -72,6 +75,9 @@ func mapFromToken(idx int, token Dependency) map[int]paramIndex { } var ( + // Empty is the empty array of providers + Empty = A.Empty[Provider]() + mergeTokenMaps = R.UnionMonoid[int](R.UnionLastSemigroup[int, int]()) foldDeps = A.FoldMapWithIndex[Dependency](mergeTokenMaps)(mapFromToken) mergeMaps = R.UnionLastMonoid[int, any]() @@ -127,15 +133,13 @@ var ( } ) -type Mapping = map[int]paramIndex - func getAt[T any](ar []T) func(idx int) T { return func(idx int) T { return ar[idx] } } -func handleMapping(mp Mapping) func(res []IOE.IOEither[error, any]) IOE.IOEither[error, []any] { +func handleMapping(mp mapping) func(res []IOE.IOEither[error, any]) IOE.IOEither[error, []any] { preFct := F.Pipe1( mp, R.Collect(func(idx int, p paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] { diff --git a/endomorphism/curry.go b/endomorphism/curry.go new file mode 100644 index 0000000..de37977 --- /dev/null +++ b/endomorphism/curry.go @@ -0,0 +1,30 @@ +// 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 endomorphism + +import ( + G "github.com/IBM/fp-go/endomorphism/generic" +) + +// Curry2 curries a binary function +func Curry2[FCT ~func(T0, T1) T1, T0, T1 any](f FCT) func(T0) Endomorphism[T1] { + return G.Curry2[Endomorphism[T1]](f) +} + +// Curry3 curries a ternary function +func Curry3[FCT ~func(T0, T1, T2) T2, T0, T1, T2 any](f FCT) func(T0) func(T1) Endomorphism[T2] { + return G.Curry3[Endomorphism[T2]](f) +} diff --git a/endomorphism/generic/curry.go b/endomorphism/generic/curry.go new file mode 100644 index 0000000..e7e41e2 --- /dev/null +++ b/endomorphism/generic/curry.go @@ -0,0 +1,36 @@ +// 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 generic + +// Curry2 is a duplicate of [F.Curry2] but because of the type system it's not compatible otherwise +func Curry2[GT1 ~func(T1) T1, FCT ~func(T0, T1) T1, T0, T1 any](f FCT) func(T0) GT1 { + return func(t0 T0) GT1 { + return func(t1 T1) T1 { + return f(t0, t1) + } + } +} + +// Curry2 is a duplicate of [F.Curry2] but because of the type system it's not compatible otherwise +func Curry3[GT2 ~func(T2) T2, FCT ~func(T0, T1, T2) T2, T0, T1, T2 any](f FCT) func(T0) func(T1) GT2 { + return func(t0 T0) func(T1) GT2 { + return func(t1 T1) GT2 { + return func(t2 T2) T2 { + return f(t0, t1, t2) + } + } + } +} diff --git a/http/form/form.go b/http/form/form.go index 5e52eda..20dc5fe 100644 --- a/http/form/form.go +++ b/http/form/form.go @@ -58,10 +58,9 @@ var ( // WithValue creates a [FormBuilder] for a certain field func WithValue(name string) func(value string) Endomorphism { - return F.Flow3( + return F.Flow2( O.Of[string], AtValue(name).Set, - ENDO.Of[func(url.Values) url.Values], ) } diff --git a/ioeither/http/builder/builder.go b/ioeither/http/builder/builder.go index 8d4299b..01db23e 100644 --- a/ioeither/http/builder/builder.go +++ b/ioeither/http/builder/builder.go @@ -70,25 +70,15 @@ var ( noBody = O.None[IOE.IOEither[error, []byte]]() // WithMethod creates a [BuilderBuilder] for a certain method - WithMethod = F.Flow2( - Method.Set, - ENDO.Of[func(*Builder) *Builder], - ) + WithMethod = Method.Set // WithUrl creates a [BuilderBuilder] for a certain method - WithUrl = F.Flow2( - Url.Set, - ENDO.Of[func(*Builder) *Builder], - ) + WithUrl = Url.Set // WithHeaders creates a [BuilderBuilder] for a set of headers - WithHeaders = F.Flow2( - Headers.Set, - ENDO.Of[func(*Builder) *Builder], - ) + WithHeaders = Headers.Set // WithBody creates a [BuilderBuilder] for a request body - WithBody = F.Flow3( + WithBody = F.Flow2( O.Of[IOE.IOEither[error, []byte]], Body.Set, - ENDO.Of[func(*Builder) *Builder], ) // WithContentType adds the content type header WithContentType = WithHeader("Content-Type") @@ -106,10 +96,9 @@ var ( Requester = (*Builder).Requester // WithoutBody creates a [BuilderBuilder] to remove the body - WithoutBody = F.Pipe2( + WithoutBody = F.Pipe1( noBody, Body.Set, - ENDO.Of[func(*Builder) *Builder], ) ) @@ -216,7 +205,7 @@ func Header(name string) L.Lens[*Builder, O.Option[string]] { LZ.Map(delHeader(name)), ) - return L.MakeLens[*Builder, O.Option[string]](get, func(b *Builder, value O.Option[string]) *Builder { + return L.MakeLens(get, func(b *Builder, value O.Option[string]) *Builder { cpy := b.clone() return F.Pipe1( value, @@ -227,10 +216,9 @@ func Header(name string) L.Lens[*Builder, O.Option[string]] { // WithHeader creates a [BuilderBuilder] for a certain header func WithHeader(name string) func(value string) Endomorphism { - return F.Flow3( + return F.Flow2( O.Of[string], Header(name).Set, - ENDO.Of[func(*Builder) *Builder], ) } diff --git a/optics/iso/iso.go b/optics/iso/iso.go index 7d5f548..9afac4f 100644 --- a/optics/iso/iso.go +++ b/optics/iso/iso.go @@ -17,6 +17,7 @@ package iso import ( + EM "github.com/IBM/fp-go/endomorphism" F "github.com/IBM/fp-go/function" ) @@ -52,7 +53,7 @@ func Reverse[S, A any](sa Iso[S, A]) Iso[A, S] { ) } -func modify[S, A any](f func(A) A, sa Iso[S, A], s S) S { +func modify[FCT ~func(A) A, S, A any](f FCT, sa Iso[S, A], s S) S { return F.Pipe3( s, sa.Get, @@ -62,8 +63,8 @@ func modify[S, A any](f func(A) A, sa Iso[S, A], s S) S { } // Modify applies a transformation -func Modify[S, A any](f func(A) A) func(Iso[S, A]) func(S) S { - return F.Curry3(modify[S, A])(f) +func Modify[S any, FCT ~func(A) A, A any](f FCT) func(Iso[S, A]) EM.Endomorphism[S] { + return EM.Curry3(modify[FCT, S, A])(f) } // Wrap wraps the value diff --git a/optics/iso/lens/lens.go b/optics/iso/lens/lens.go index b0d46a3..428a60a 100644 --- a/optics/iso/lens/lens.go +++ b/optics/iso/lens/lens.go @@ -16,6 +16,7 @@ package lens import ( + EM "github.com/IBM/fp-go/endomorphism" F "github.com/IBM/fp-go/function" I "github.com/IBM/fp-go/optics/iso" L "github.com/IBM/fp-go/optics/lens" @@ -23,10 +24,10 @@ import ( // IsoAsLens converts an `Iso` to a `Lens` func IsoAsLens[S, A any](sa I.Iso[S, A]) L.Lens[S, A] { - return L.MakeLensCurried(sa.Get, F.Flow2(sa.ReverseGet, F.Constant1[S, S])) + return L.MakeLensCurried(sa.Get, F.Flow2(sa.ReverseGet, F.Flow2(F.Constant1[S, S], EM.Of[func(S) S]))) } // IsoAsLensRef converts an `Iso` to a `Lens` func IsoAsLensRef[S, A any](sa I.Iso[*S, A]) L.Lens[*S, A] { - return L.MakeLensRefCurried(sa.Get, F.Flow2(sa.ReverseGet, F.Constant1[*S, *S])) + return L.MakeLensRefCurried(sa.Get, F.Flow2(sa.ReverseGet, F.Flow2(F.Constant1[*S, *S], EM.Of[func(*S) *S]))) } diff --git a/optics/lens/lens.go b/optics/lens/lens.go index 807fd3d..3e8c59e 100644 --- a/optics/lens/lens.go +++ b/optics/lens/lens.go @@ -17,8 +17,8 @@ package lens import ( + EM "github.com/IBM/fp-go/endomorphism" F "github.com/IBM/fp-go/function" - I "github.com/IBM/fp-go/identity" O "github.com/IBM/fp-go/option" ) @@ -26,13 +26,13 @@ type ( // Lens is a reference to a subpart of a data type Lens[S, A any] struct { Get func(s S) A - Set func(a A) func(S) S + Set func(a A) EM.Endomorphism[S] } ) // setCopy wraps a setter for a pointer into a setter that first creates a copy before // modifying that copy -func setCopy[S, A any](setter func(*S, A) *S) func(s *S, a A) *S { +func setCopy[SET ~func(*S, A) *S, S, A any](setter SET) func(s *S, a A) *S { return func(s *S, a A) *S { copy := *s return setter(©, a) @@ -41,8 +41,8 @@ func setCopy[S, A any](setter func(*S, A) *S) func(s *S, a A) *S { // setCopyCurried wraps a setter for a pointer into a setter that first creates a copy before // modifying that copy -func setCopyCurried[S, A any](setter func(A) func(*S) *S) func(a A) func(*S) *S { - return func(a A) func(*S) *S { +func setCopyCurried[SET ~func(A) EM.Endomorphism[*S], S, A any](setter SET) func(a A) EM.Endomorphism[*S] { + return func(a A) EM.Endomorphism[*S] { seta := setter(a) return func(s *S) *S { copy := *s @@ -51,53 +51,53 @@ func setCopyCurried[S, A any](setter func(A) func(*S) *S) func(a A) func(*S) *S } } -// MakeLens creates a lens based on a getter and a setter function. Make sure that the setter creates a (shallow) copy of the +// MakeLens creates a [Lens] based on a getter and a setter function. Make sure that the setter creates a (shallow) copy of the // data. This happens automatically if the data is passed by value. For pointers consider to use `MakeLensRef` // and for other kinds of data structures that are copied by reference make sure the setter creates the copy. -func MakeLens[S, A any](get func(S) A, set func(S, A) S) Lens[S, A] { - return MakeLensCurried(get, F.Curry2(F.Swap(set))) +func MakeLens[GET ~func(S) A, SET ~func(S, A) S, S, A any](get GET, set SET) Lens[S, A] { + return MakeLensCurried(get, EM.Curry2(F.Swap(set))) } -// MakeLensCurried creates a lens based on a getter and a setter function. Make sure that the setter creates a (shallow) copy of the +// MakeLensCurried creates a [Lens] based on a getter and a setter function. Make sure that the setter creates a (shallow) copy of the // data. This happens automatically if the data is passed by value. For pointers consider to use `MakeLensRef` // and for other kinds of data structures that are copied by reference make sure the setter creates the copy. -func MakeLensCurried[S, A any](get func(S) A, set func(A) func(S) S) Lens[S, A] { +func MakeLensCurried[GET ~func(S) A, SET ~func(A) EM.Endomorphism[S], S, A any](get GET, set SET) Lens[S, A] { return Lens[S, A]{Get: get, Set: set} } -// MakeLensRef creates a lens based on a getter and a setter function. The setter passed in does not have to create a shallow +// MakeLensRef creates a [Lens] based on a getter and a setter function. The setter passed in does not have to create a shallow // copy, the implementation wraps the setter into one that copies the pointer before modifying it // -// Such a lens assumes that property A of S always exists -func MakeLensRef[S, A any](get func(*S) A, set func(*S, A) *S) Lens[*S, A] { +// Such a [Lens] assumes that property A of S always exists +func MakeLensRef[GET ~func(*S) A, SET func(*S, A) *S, S, A any](get GET, set SET) Lens[*S, A] { return MakeLens(get, setCopy(set)) } -// MakeLensRefCurried creates a lens based on a getter and a setter function. The setter passed in does not have to create a shallow +// MakeLensRefCurried creates a [Lens] based on a getter and a setter function. The setter passed in does not have to create a shallow // copy, the implementation wraps the setter into one that copies the pointer before modifying it // -// Such a lens assumes that property A of S always exists -func MakeLensRefCurried[S, A any](get func(*S) A, set func(A) func(*S) *S) Lens[*S, A] { +// Such a [Lens] assumes that property A of S always exists +func MakeLensRefCurried[S, A any](get func(*S) A, set func(A) EM.Endomorphism[*S]) Lens[*S, A] { return MakeLensCurried(get, setCopyCurried(set)) } -// Id returns a lens implementing the identity operation -func id[S any](creator func(get func(S) S, set func(S, S) S) Lens[S, S]) Lens[S, S] { +// id returns a [Lens] implementing the identity operation +func id[GET ~func(S) S, SET ~func(S, S) S, S any](creator func(get GET, set SET) Lens[S, S]) Lens[S, S] { return creator(F.Identity[S], F.Second[S, S]) } -// Id returns a lens implementing the identity operation +// Id returns a [Lens] implementing the identity operation func Id[S any]() Lens[S, S] { - return id(MakeLens[S, S]) + return id(MakeLens[EM.Endomorphism[S], func(S, S) S]) } -// IdRef returns a lens implementing the identity operation +// IdRef returns a [Lens] implementing the identity operation func IdRef[S any]() Lens[*S, *S] { - return id(MakeLensRef[S, *S]) + return id(MakeLensRef[EM.Endomorphism[*S], func(*S, *S) *S]) } // Compose combines two lenses and allows to narrow down the focus to a sub-lens -func compose[S, A, B any](creator func(get func(S) B, set func(S, B) S) Lens[S, B], ab Lens[A, B]) func(Lens[S, A]) Lens[S, B] { +func compose[GET ~func(S) B, SET ~func(S, B) S, S, A, B any](creator func(get GET, set SET) Lens[S, B], ab Lens[A, B]) func(Lens[S, A]) Lens[S, B] { abget := ab.Get abset := ab.Set return func(sa Lens[S, A]) Lens[S, B] { @@ -114,7 +114,7 @@ func compose[S, A, B any](creator func(get func(S) B, set func(S, B) S) Lens[S, // Compose combines two lenses and allows to narrow down the focus to a sub-lens func Compose[S, A, B any](ab Lens[A, B]) func(Lens[S, A]) Lens[S, B] { - return compose(MakeLens[S, B], ab) + return compose(MakeLens[func(S) B, func(S, B) S], ab) } // ComposeOption combines a `Lens` that returns an optional value with a `Lens` that returns a definite value @@ -141,7 +141,7 @@ func ComposeOption[S, B, A any](defaultA A) func(ab Lens[A, B]) func(Lens[S, O.O func(s S, ob O.Option[B]) S { return F.Pipe2( ob, - O.Fold(unseta, func(b B) func(S) S { + O.Fold(unseta, func(b B) EM.Endomorphism[S] { setbona := F.Flow2( ab.Set(b), seta, @@ -158,7 +158,7 @@ func ComposeOption[S, B, A any](defaultA A) func(ab Lens[A, B]) func(Lens[S, O.O ), ) }), - I.Ap[S, S](s), + EM.Ap(s), ) }, ) @@ -174,7 +174,7 @@ func ComposeOption[S, B, A any](defaultA A) func(ab Lens[A, B]) func(Lens[S, O.O // if the setter is called with `None[B]` and `A` does exist, 'B' is removed from 'A' func ComposeOptions[S, B, A any](defaultA A) func(ab Lens[A, O.Option[B]]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] { defa := F.Constant(defaultA) - noops := F.Constant(F.Identity[S]) + noops := EM.Identity[S] noneb := O.None[B]() return func(ab Lens[A, O.Option[B]]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] { unsetb := ab.Set(noneb) @@ -189,15 +189,15 @@ func ComposeOptions[S, B, A any](defaultA A) func(ab Lens[A, O.Option[B]]) func( sa.Get, O.Chain(ab.Get), ), - func(b O.Option[B]) func(S) S { + func(b O.Option[B]) EM.Endomorphism[S] { return func(s S) S { - return O.MonadFold(b, func() func(S) S { + return O.MonadFold(b, func() EM.Endomorphism[S] { return F.Pipe2( s, sa.Get, O.Fold(noops, F.Flow2(unsetb, seta)), ) - }, func(b B) func(S) S { + }, func(b B) EM.Endomorphism[S] { // sets a B onto an A setb := F.Flow2( ab.Set(O.Some(b)), @@ -218,20 +218,20 @@ func ComposeOptions[S, B, A any](defaultA A) func(ab Lens[A, O.Option[B]]) func( // Compose combines two lenses and allows to narrow down the focus to a sub-lens func ComposeRef[S, A, B any](ab Lens[A, B]) func(Lens[*S, A]) Lens[*S, B] { - return compose(MakeLensRef[S, B], ab) + return compose(MakeLensRef[func(*S) B, func(*S, B) *S], ab) } -func modify[S, A any](f func(A) A, sa Lens[S, A], s S) S { +func modify[FCT ~func(A) A, S, A any](f FCT, sa Lens[S, A], s S) S { return sa.Set(f(sa.Get(s)))(s) } -// Modify changes a property of a lens by invoking a transformation function +// Modify changes a property of a [Lens] by invoking a transformation function // if the transformed property has not changes, the method returns the original state -func Modify[S, A any](f func(A) A) func(Lens[S, A]) func(S) S { - return F.Curry3(modify[S, A])(f) +func Modify[S any, FCT ~func(A) A, A any](f FCT) func(Lens[S, A]) EM.Endomorphism[S] { + return EM.Curry3(modify[FCT, S, A])(f) } -func IMap[E, A, B any](ab func(A) B, ba func(B) A) func(Lens[E, A]) Lens[E, B] { +func IMap[E any, AB ~func(A) B, BA ~func(B) A, A, B any](ab AB, ba BA) func(Lens[E, A]) Lens[E, B] { return func(ea Lens[E, A]) Lens[E, B] { return Lens[E, B]{Get: F.Flow2(ea.Get, ab), Set: F.Flow2(ba, ea.Set)} } @@ -239,7 +239,7 @@ func IMap[E, A, B any](ab func(A) B, ba func(B) A) func(Lens[E, A]) Lens[E, B] { // fromPredicate returns a `Lens` for a property accessibly as a getter and setter that can be optional // if the optional value is set then the nil value will be set instead -func fromPredicate[S, A any](creator func(get func(S) O.Option[A], set func(S, O.Option[A]) S) Lens[S, O.Option[A]], pred func(A) bool, nilValue A) func(sa Lens[S, A]) Lens[S, O.Option[A]] { +func fromPredicate[GET ~func(S) O.Option[A], SET ~func(S, O.Option[A]) S, S, A any](creator func(get GET, set SET) Lens[S, O.Option[A]], pred func(A) bool, nilValue A) func(sa Lens[S, A]) Lens[S, O.Option[A]] { fromPred := O.FromPredicate(pred) return func(sa Lens[S, A]) Lens[S, O.Option[A]] { fold := O.Fold(F.Bind1of1(sa.Set)(nilValue), sa.Set) @@ -247,7 +247,7 @@ func fromPredicate[S, A any](creator func(get func(S) O.Option[A], set func(S, O return F.Pipe2( a, fold, - I.Ap[S, S](s), + EM.Ap(s), ) }) } @@ -256,13 +256,13 @@ func fromPredicate[S, A any](creator func(get func(S) O.Option[A], set func(S, O // FromPredicate returns a `Lens` for a property accessibly as a getter and setter that can be optional // if the optional value is set then the nil value will be set instead func FromPredicate[S, A any](pred func(A) bool, nilValue A) func(sa Lens[S, A]) Lens[S, O.Option[A]] { - return fromPredicate(MakeLens[S, O.Option[A]], pred, nilValue) + return fromPredicate(MakeLens[func(S) O.Option[A], func(S, O.Option[A]) S], pred, nilValue) } // FromPredicateRef returns a `Lens` for a property accessibly as a getter and setter that can be optional // if the optional value is set then the nil value will be set instead func FromPredicateRef[S, A any](pred func(A) bool, nilValue A) func(sa Lens[*S, A]) Lens[*S, O.Option[A]] { - return fromPredicate(MakeLensRef[S, O.Option[A]], pred, nilValue) + return fromPredicate(MakeLensRef[func(*S) O.Option[A], func(*S, O.Option[A]) *S], pred, nilValue) } // FromPredicate returns a `Lens` for a property accessibly as a getter and setter that can be optional @@ -278,7 +278,7 @@ func FromNillableRef[S, A any](sa Lens[*S, *A]) Lens[*S, O.Option[*A]] { } // fromNullableProp returns a `Lens` from a property that may be optional. The getter returns a default value for these items -func fromNullableProp[S, A any](creator func(get func(S) A, set func(S, A) S) Lens[S, A], isNullable func(A) O.Option[A], defaultValue A) func(sa Lens[S, A]) Lens[S, A] { +func fromNullableProp[GET ~func(S) A, SET ~func(S, A) S, S, A any](creator func(get GET, set SET) Lens[S, A], isNullable func(A) O.Option[A], defaultValue A) func(sa Lens[S, A]) Lens[S, A] { return func(sa Lens[S, A]) Lens[S, A] { return creator(F.Flow3( sa.Get, @@ -293,16 +293,16 @@ func fromNullableProp[S, A any](creator func(get func(S) A, set func(S, A) S) Le // FromNullableProp returns a `Lens` from a property that may be optional. The getter returns a default value for these items func FromNullableProp[S, A any](isNullable func(A) O.Option[A], defaultValue A) func(sa Lens[S, A]) Lens[S, A] { - return fromNullableProp(MakeLens[S, A], isNullable, defaultValue) + return fromNullableProp(MakeLens[func(S) A, func(S, A) S], isNullable, defaultValue) } // FromNullablePropRef returns a `Lens` from a property that may be optional. The getter returns a default value for these items func FromNullablePropRef[S, A any](isNullable func(A) O.Option[A], defaultValue A) func(sa Lens[*S, A]) Lens[*S, A] { - return fromNullableProp(MakeLensRef[S, A], isNullable, defaultValue) + return fromNullableProp(MakeLensRef[func(*S) A, func(*S, A) *S], isNullable, defaultValue) } // fromFromOption returns a `Lens` from an option property. The getter returns a default value the setter will always set the some option -func fromOption[S, A any](creator func(get func(S) A, set func(S, A) S) Lens[S, A], defaultValue A) func(sa Lens[S, O.Option[A]]) Lens[S, A] { +func fromOption[GET ~func(S) A, SET ~func(S, A) S, S, A any](creator func(get GET, set SET) Lens[S, A], defaultValue A) func(sa Lens[S, O.Option[A]]) Lens[S, A] { return func(sa Lens[S, O.Option[A]]) Lens[S, A] { return creator(F.Flow2( sa.Get, @@ -316,10 +316,10 @@ func fromOption[S, A any](creator func(get func(S) A, set func(S, A) S) Lens[S, // FromFromOption returns a `Lens` from an option property. The getter returns a default value the setter will always set the some option func FromOption[S, A any](defaultValue A) func(sa Lens[S, O.Option[A]]) Lens[S, A] { - return fromOption(MakeLens[S, A], defaultValue) + return fromOption(MakeLens[func(S) A, func(S, A) S], defaultValue) } // FromFromOptionRef returns a `Lens` from an option property. The getter returns a default value the setter will always set the some option func FromOptionRef[S, A any](defaultValue A) func(sa Lens[*S, O.Option[A]]) Lens[*S, A] { - return fromOption(MakeLensRef[S, A], defaultValue) + return fromOption(MakeLensRef[func(*S) A, func(*S, A) *S], defaultValue) } diff --git a/optics/optional/optional.go b/optics/optional/optional.go index 11b47f8..36ca3e7 100644 --- a/optics/optional/optional.go +++ b/optics/optional/optional.go @@ -18,6 +18,7 @@ package optional import ( + EM "github.com/IBM/fp-go/endomorphism" F "github.com/IBM/fp-go/function" O "github.com/IBM/fp-go/option" ) @@ -25,12 +26,12 @@ import ( // Optional is an optional reference to a subpart of a data type type Optional[S, A any] struct { GetOption func(s S) O.Option[A] - Set func(a A) func(S) S + Set func(a A) EM.Endomorphism[S] } // setCopy wraps a setter for a pointer into a setter that first creates a copy before // modifying that copy -func setCopy[S, A any](setter func(*S, A) *S) func(s *S, a A) *S { +func setCopy[SET ~func(*S, A) *S, S, A any](setter SET) func(s *S, a A) *S { return func(s *S, a A) *S { copy := *s return setter(©, a) @@ -41,7 +42,7 @@ func setCopy[S, A any](setter func(*S, A) *S) func(s *S, a A) *S { // data. This happens automatically if the data is passed by value. For pointers consider to use `MakeOptionalRef` // and for other kinds of data structures that are copied by reference make sure the setter creates the copy. func MakeOptional[S, A any](get func(S) O.Option[A], set func(S, A) S) Optional[S, A] { - return Optional[S, A]{GetOption: get, Set: F.Curry2(F.Swap(set))} + return Optional[S, A]{GetOption: get, Set: EM.Curry2(F.Swap(set))} } // MakeOptionalRef creates an Optional based on a getter and a setter function. The setter passed in does not have to create a shallow @@ -168,7 +169,7 @@ func ichain[S, A, B any](sa Optional[S, A], ab func(A) O.Option[B], ba func(B) O return MakeOptional( F.Flow2(sa.GetOption, O.Chain(ab)), func(s S, b B) S { - return O.MonadFold(ba(b), F.Constant(F.Identity[S]), sa.Set)(s) + return O.MonadFold(ba(b), EM.Identity[S], sa.Set)(s) }, ) } diff --git a/optics/prism/prism.go b/optics/prism/prism.go index 976811f..80d40c5 100644 --- a/optics/prism/prism.go +++ b/optics/prism/prism.go @@ -17,6 +17,7 @@ package prism import ( + EM "github.com/IBM/fp-go/endomorphism" F "github.com/IBM/fp-go/function" O "github.com/IBM/fp-go/option" ) @@ -86,12 +87,12 @@ func prismModify[S, A any](f func(A) A, sa Prism[S, A], s S) S { ) } -func prismSet[S, A any](a A) func(Prism[S, A]) func(S) S { - return F.Curry3(prismModify[S, A])(F.Constant1[A](a)) +func prismSet[S, A any](a A) func(Prism[S, A]) EM.Endomorphism[S] { + return EM.Curry3(prismModify[S, A])(F.Constant1[A](a)) } -func Set[S, A any](a A) func(Prism[S, A]) func(S) S { - return F.Curry3(prismModify[S, A])(F.Constant1[A](a)) +func Set[S, A any](a A) func(Prism[S, A]) EM.Endomorphism[S] { + return EM.Curry3(prismModify[S, A])(F.Constant1[A](a)) } func prismSome[A any]() Prism[O.Option[A], A] { @@ -103,14 +104,14 @@ func Some[S, A any](soa Prism[S, O.Option[A]]) Prism[S, A] { return Compose[S](prismSome[A]())(soa) } -func imap[S, A, B any](sa Prism[S, A], ab func(A) B, ba func(B) A) Prism[S, B] { +func imap[S any, AB ~func(A) B, BA ~func(B) A, A, B any](sa Prism[S, A], ab AB, ba BA) Prism[S, B] { return MakePrism( F.Flow2(sa.GetOption, O.Map(ab)), F.Flow2(ba, sa.ReverseGet), ) } -func IMap[S, A, B any](ab func(A) B, ba func(B) A) func(Prism[S, A]) Prism[S, B] { +func IMap[S any, AB ~func(A) B, BA ~func(B) A, A, B any](ab AB, ba BA) func(Prism[S, A]) Prism[S, B] { return func(sa Prism[S, A]) Prism[S, B] { return imap(sa, ab, ba) }