mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-10 22:31:32 +02:00
fix: use endomorphism
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
@@ -308,10 +308,16 @@ func SliceRight[A any](start int) func([]A) []A {
|
|||||||
return G.SliceRight[[]A](start)
|
return G.SliceRight[[]A](start)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy creates a shallow copy of the array
|
||||||
func Copy[A any](b []A) []A {
|
func Copy[A any](b []A) []A {
|
||||||
return G.Copy(b)
|
return G.Copy(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clone creates a deep copy of the array using the provided endomorphism to clone the values
|
||||||
|
func Clone[A any](f func(A) A) func(as []A) []A {
|
||||||
|
return G.Clone[[]A](f)
|
||||||
|
}
|
||||||
|
|
||||||
// FoldMap maps and folds an array. Map the Array passing each value to the iterating function. Then fold the results using the provided Monoid.
|
// FoldMap maps and folds an array. Map the Array passing each value to the iterating function. Then fold the results using the provided Monoid.
|
||||||
func FoldMap[A, B any](m M.Monoid[B]) func(func(A) B) func([]A) B {
|
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)
|
||||||
|
@@ -304,6 +304,11 @@ func Copy[AS ~[]A, A any](b AS) AS {
|
|||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Clone[AS ~[]A, A any](f func(A) A) func(as AS) AS {
|
||||||
|
// implementation assumes that map does not optimize for the empty array
|
||||||
|
return Map[AS, AS](f)
|
||||||
|
}
|
||||||
|
|
||||||
func FoldMap[AS ~[]A, A, B any](m M.Monoid[B]) func(func(A) B) func(AS) B {
|
func FoldMap[AS ~[]A, A, B any](m M.Monoid[B]) func(func(A) B) func(AS) B {
|
||||||
return func(f func(A) B) func(AS) B {
|
return func(f func(A) B) func(AS) B {
|
||||||
return func(as AS) B {
|
return func(as AS) B {
|
||||||
|
51
endomorphism/generic/monoid.go
Normal file
51
endomorphism/generic/monoid.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
import (
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
M "github.com/IBM/fp-go/monoid"
|
||||||
|
S "github.com/IBM/fp-go/semigroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Of converts any function to an [Endomorphism]
|
||||||
|
func Of[ENDO ~func(A) A, F ~func(A) A, A any](f F) ENDO {
|
||||||
|
return func(a A) A {
|
||||||
|
return f(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Identity[ENDO ~func(A) A, A any]() ENDO {
|
||||||
|
return func(a A) A {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Compose[ENDO ~func(A) A, A any](f1, f2 ENDO) ENDO {
|
||||||
|
return func(a A) A {
|
||||||
|
return F.Pipe2(a, f1, f2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Semigroup for the Endomorphism where the `concat` operation is the usual function composition.
|
||||||
|
func Semigroup[ENDO ~func(A) A, A any]() S.Semigroup[ENDO] {
|
||||||
|
return S.MakeSemigroup(Compose[ENDO])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Monoid for the Endomorphism where the `concat` operation is the usual function composition.
|
||||||
|
func Monoid[ENDO ~func(A) A, A any]() M.Monoid[ENDO] {
|
||||||
|
return M.MakeMonoid(Compose[ENDO], Identity[ENDO]())
|
||||||
|
}
|
@@ -16,17 +16,30 @@
|
|||||||
package endomorphism
|
package endomorphism
|
||||||
|
|
||||||
import (
|
import (
|
||||||
F "github.com/IBM/fp-go/function"
|
G "github.com/IBM/fp-go/endomorphism/generic"
|
||||||
M "github.com/IBM/fp-go/monoid"
|
M "github.com/IBM/fp-go/monoid"
|
||||||
S "github.com/IBM/fp-go/semigroup"
|
S "github.com/IBM/fp-go/semigroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Endomorphism is a function that
|
||||||
|
type Endomorphism[A any] func(A) A
|
||||||
|
|
||||||
|
// Of converts any function to an [Endomorphism]
|
||||||
|
func Of[F ~func(A) A, A any](f F) Endomorphism[A] {
|
||||||
|
return G.Of[Endomorphism[A]](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identity returns the identity [Endomorphism]
|
||||||
|
func Identity[A any]() Endomorphism[A] {
|
||||||
|
return G.Identity[Endomorphism[A]]()
|
||||||
|
}
|
||||||
|
|
||||||
// Semigroup for the Endomorphism where the `concat` operation is the usual function composition.
|
// Semigroup for the Endomorphism where the `concat` operation is the usual function composition.
|
||||||
func Semigroup[A any]() S.Semigroup[func(A) A] {
|
func Semigroup[A any]() S.Semigroup[Endomorphism[A]] {
|
||||||
return S.MakeSemigroup(F.Flow2[func(A) A, func(A) A])
|
return G.Semigroup[Endomorphism[A]]()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Monoid for the Endomorphism where the `concat` operation is the usual function composition.
|
// Monoid for the Endomorphism where the `concat` operation is the usual function composition.
|
||||||
func Monoid[A any]() M.Monoid[func(A) A] {
|
func Monoid[A any]() M.Monoid[Endomorphism[A]] {
|
||||||
return M.MakeMonoid(F.Flow2[func(A) A, func(A) A], F.Identity[A])
|
return G.Monoid[Endomorphism[A]]()
|
||||||
}
|
}
|
||||||
|
@@ -19,6 +19,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
A "github.com/IBM/fp-go/array"
|
A "github.com/IBM/fp-go/array"
|
||||||
|
ENDO "github.com/IBM/fp-go/endomorphism"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
L "github.com/IBM/fp-go/optics/lens"
|
L "github.com/IBM/fp-go/optics/lens"
|
||||||
LA "github.com/IBM/fp-go/optics/lens/array"
|
LA "github.com/IBM/fp-go/optics/lens/array"
|
||||||
@@ -27,8 +28,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// FormBuilder returns a function that transforms a form
|
// FormEndomorphism returns an [ENDO.Endomorphism] that transforms a form
|
||||||
FormBuilder = func(url.Values) url.Values
|
FormEndomorphism = ENDO.Endomorphism[url.Values]
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -53,14 +54,15 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// WithValue creates a [FormBuilder] for a certain field
|
// WithValue creates a [FormBuilder] for a certain field
|
||||||
func WithValue(name string) func(value string) FormBuilder {
|
func WithValue(name string) func(value string) FormEndomorphism {
|
||||||
return F.Flow2(
|
return F.Flow3(
|
||||||
O.Of[string],
|
O.Of[string],
|
||||||
AtValue(name).Set,
|
AtValue(name).Set,
|
||||||
|
ENDO.Of[func(url.Values) url.Values],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithoutValue creates a [FormBuilder] that removes a field
|
// WithoutValue creates a [FormBuilder] that removes a field
|
||||||
func WithoutValue(name string) FormBuilder {
|
func WithoutValue(name string) FormEndomorphism {
|
||||||
return AtValue(name).Set(noField)
|
return AtValue(name).Set(noField)
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
ENDO "github.com/IBM/fp-go/endomorphism"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
IOE "github.com/IBM/fp-go/ioeither"
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
IOEH "github.com/IBM/fp-go/ioeither/http"
|
IOEH "github.com/IBM/fp-go/ioeither/http"
|
||||||
@@ -39,8 +40,8 @@ type (
|
|||||||
body O.Option[IOE.IOEither[error, []byte]]
|
body O.Option[IOE.IOEither[error, []byte]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuilderBuilder returns a function that transforms a builder
|
// BuilderEndomorphism returns an [ENDO.Endomorphism] that transforms a builder
|
||||||
BuilderBuilder = func(*Builder) *Builder
|
BuilderEndomorphism = ENDO.Endomorphism[*Builder]
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -208,20 +209,21 @@ func Header(name string) L.Lens[*Builder, O.Option[string]] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WithHeader creates a [BuilderBuilder] for a certain header
|
// WithHeader creates a [BuilderBuilder] for a certain header
|
||||||
func WithHeader(name string) func(value string) BuilderBuilder {
|
func WithHeader(name string) func(value string) BuilderEndomorphism {
|
||||||
return F.Flow2(
|
return F.Flow3(
|
||||||
O.Of[string],
|
O.Of[string],
|
||||||
Header(name).Set,
|
Header(name).Set,
|
||||||
|
ENDO.Of[func(*Builder) *Builder],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithoutHeader creates a [BuilderBuilder] to remove a certain header
|
// WithoutHeader creates a [BuilderBuilder] to remove a certain header
|
||||||
func WithoutHeader(name string) BuilderBuilder {
|
func WithoutHeader(name string) BuilderEndomorphism {
|
||||||
return Header(name).Set(noHeader)
|
return Header(name).Set(noHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithFormData creates a [BuilderBuilder] to send form data payload
|
// WithFormData creates a [BuilderBuilder] to send form data payload
|
||||||
func WithFormData(value url.Values) BuilderBuilder {
|
func WithFormData(value url.Values) BuilderEndomorphism {
|
||||||
return F.Flow2(
|
return F.Flow2(
|
||||||
F.Pipe4(
|
F.Pipe4(
|
||||||
value,
|
value,
|
||||||
@@ -235,7 +237,7 @@ func WithFormData(value url.Values) BuilderBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WithJson creates a [BuilderBuilder] to send JSON payload
|
// WithJson creates a [BuilderBuilder] to send JSON payload
|
||||||
func WithJson[T any](data T) BuilderBuilder {
|
func WithJson[T any](data T) BuilderEndomorphism {
|
||||||
return F.Flow2(
|
return F.Flow2(
|
||||||
F.Pipe3(
|
F.Pipe3(
|
||||||
data,
|
data,
|
||||||
|
@@ -531,3 +531,12 @@ func MonadFlap[GFAB ~map[K]func(A) B, GB ~map[K]B, K comparable, A, B any](fab G
|
|||||||
func Flap[GFAB ~map[K]func(A) B, GB ~map[K]B, K comparable, A, B any](a A) func(GFAB) GB {
|
func Flap[GFAB ~map[K]func(A) B, GB ~map[K]B, K comparable, A, B any](a A) func(GFAB) GB {
|
||||||
return FC.Flap(MonadMap[GFAB, GB], a)
|
return FC.Flap(MonadMap[GFAB, GB], a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Copy[M ~map[K]V, K comparable, V any](m M) M {
|
||||||
|
return duplicate(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Clone[M ~map[K]V, K comparable, V any](f func(V) V) func(m M) M {
|
||||||
|
// impementation assumes that map does not optimize for the empty map
|
||||||
|
return Map[M, M](f)
|
||||||
|
}
|
||||||
|
@@ -284,3 +284,13 @@ func MonadFlap[B any, K comparable, A any](fab map[K]func(A) B, a A) map[K]B {
|
|||||||
func Flap[B any, K comparable, A any](a A) func(map[K]func(A) B) map[K]B {
|
func Flap[B any, K comparable, A any](a A) func(map[K]func(A) B) map[K]B {
|
||||||
return G.Flap[map[K]func(A) B, map[K]B](a)
|
return G.Flap[map[K]func(A) B, map[K]B](a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy creates a shallow copy of the map
|
||||||
|
func Copy[K comparable, V any](m map[K]V) map[K]V {
|
||||||
|
return G.Copy[map[K]V](m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
return G.Clone[map[K]V](f)
|
||||||
|
}
|
||||||
|
@@ -21,6 +21,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
A "github.com/IBM/fp-go/array"
|
||||||
"github.com/IBM/fp-go/internal/utils"
|
"github.com/IBM/fp-go/internal/utils"
|
||||||
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"
|
||||||
@@ -131,3 +132,20 @@ func ExampleValuesOrd() {
|
|||||||
// Output: [c b a]
|
// Output: [c b a]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCopyVsClone(t *testing.T) {
|
||||||
|
slc := []string{"b", "c"}
|
||||||
|
src := map[string][]string{
|
||||||
|
"a": slc,
|
||||||
|
}
|
||||||
|
// make a shallow copy
|
||||||
|
cpy := Copy(src)
|
||||||
|
// make a deep copy
|
||||||
|
cln := Clone[string](A.Copy[string])(src)
|
||||||
|
|
||||||
|
assert.Equal(t, cpy, cln)
|
||||||
|
// make a modification to the original slice
|
||||||
|
slc[0] = "d"
|
||||||
|
assert.NotEqual(t, cpy, cln)
|
||||||
|
assert.Equal(t, src, cpy)
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user