diff --git a/constant/const.go b/constant/const.go index 726621a..f95c5a8 100644 --- a/constant/const.go +++ b/constant/const.go @@ -22,30 +22,28 @@ import ( ) type Const[E, A any] struct { - Value E + value E } func Make[E, A any](e E) Const[E, A] { - return Const[E, A]{Value: e} + return Const[E, A]{value: e} } func Unwrap[E, A any](c Const[E, A]) E { - return c.Value + return c.value } func Of[E, A any](m M.Monoid[E]) func(A) Const[E, A] { - return func(a A) Const[E, A] { - return Make[E, A](m.Empty()) - } + return F.Constant1[A](Make[E, A](m.Empty())) } func MonadMap[E, A, B any](fa Const[E, A], f func(A) B) Const[E, B] { - return Make[E, B](fa.Value) + return Make[E, B](fa.value) } func MonadAp[E, A, B any](s S.Semigroup[E]) func(fab Const[E, func(A) B], fa Const[E, A]) Const[E, B] { return func(fab Const[E, func(A) B], fa Const[E, A]) Const[E, B] { - return Make[E, B](s.Concat(fab.Value, fa.Value)) + return Make[E, B](s.Concat(fab.value, fa.value)) } } diff --git a/ioeither/ioeither.go b/ioeither/ioeither.go index cfd76e6..a9842dc 100644 --- a/ioeither/ioeither.go +++ b/ioeither/ioeither.go @@ -125,10 +125,29 @@ func MonadAp[B, E, A any](mab IOEither[E, func(A) B], ma IOEither[E, A]) IOEithe return G.MonadAp[IOEither[E, B]](mab, ma) } +// Ap is an alias of [ApPar] func Ap[B, E, A any](ma IOEither[E, A]) func(IOEither[E, func(A) B]) IOEither[E, B] { return G.Ap[IOEither[E, B], IOEither[E, func(A) B]](ma) } +func MonadApPar[B, E, A any](mab IOEither[E, func(A) B], ma IOEither[E, A]) IOEither[E, B] { + return G.MonadApPar[IOEither[E, B]](mab, ma) +} + +// ApPar applies function and value in parallel +func ApPar[B, E, A any](ma IOEither[E, A]) func(IOEither[E, func(A) B]) IOEither[E, B] { + return G.ApPar[IOEither[E, B], IOEither[E, func(A) B]](ma) +} + +func MonadApSeq[B, E, A any](mab IOEither[E, func(A) B], ma IOEither[E, A]) IOEither[E, B] { + return G.MonadApSeq[IOEither[E, B]](mab, ma) +} + +// ApSeq applies function and value sequentially +func ApSeq[B, E, A any](ma IOEither[E, A]) func(IOEither[E, func(A) B]) IOEither[E, B] { + return G.ApSeq[IOEither[E, B], IOEither[E, func(A) B]](ma) +} + func Flatten[E, A any](mma IOEither[E, IOEither[E, A]]) IOEither[E, A] { return G.Flatten(mma) } diff --git a/optics/traversal/array/const/traversal.go b/optics/traversal/array/const/traversal.go index 0637df9..fb34315 100644 --- a/optics/traversal/array/const/traversal.go +++ b/optics/traversal/array/const/traversal.go @@ -22,7 +22,7 @@ import ( G "github.com/IBM/fp-go/optics/traversal/generic" ) -// FromArray returns a traversal from an array for the identity monad +// FromArray returns a traversal from an array for the identity [Monoid] func FromArray[E, A any](m M.Monoid[E]) G.Traversal[[]A, A, C.Const[E, []A], C.Const[E, A]] { return AR.FromArray[[]A, E, A](m) } diff --git a/renovate.json b/renovate.json index 8018a3e..7ead388 100644 --- a/renovate.json +++ b/renovate.json @@ -6,6 +6,15 @@ ], "rangeStrategy": "bump", "packageRules": [ + { + "matchManagers": [ + "gomod" + ], + "matchDepTypes": [ + "golang" + ], + "enabled": false + }, { "matchUpdateTypes": [ "major", diff --git a/samples/presentation/examples/example_either_test.go b/samples/presentation/examples/example_either_test.go new file mode 100644 index 0000000..f3785ac --- /dev/null +++ b/samples/presentation/examples/example_either_test.go @@ -0,0 +1,103 @@ +// 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 examples + +import ( + "fmt" + "strconv" + + E "github.com/IBM/fp-go/either" + F "github.com/IBM/fp-go/function" + S "github.com/IBM/fp-go/string" +) + +func validatePort(port int) (int, error) { + if port > 0 { + return port, nil + } + return 0, fmt.Errorf("Value %d is not a valid port number", port) +} + +func Example_either_monad() { + + // func(string) E.Either[error, int] + atoi := E.Eitherize1(strconv.Atoi) + // func(int) E.Either[error, int] + valPort := E.Eitherize1(validatePort) + + // func(string) E.Either[error, string] + makeUrl := F.Flow3( + atoi, + E.Chain(valPort), + E.Map[error](S.Format[int]("http://localhost:%d")), + ) + + fmt.Println(makeUrl("8080")) + + // Output: + // Right[, string](http://localhost:8080) +} + +func Example_either_idiomatic() { + + makeUrl := func(port string) (string, error) { + parsed, err := strconv.Atoi(port) + if err != nil { + return "", err + } + valid, err := validatePort(parsed) + if err != nil { + return "", err + } + return fmt.Sprintf("http://localhost:%d", valid), nil + } + + url, err := makeUrl("8080") + if err != nil { + panic(err) + } + fmt.Println(url) + + // Output: + // http://localhost:8080 +} + +func Example_either_worlds() { + + // func(string) E.Either[error, int] + atoi := E.Eitherize1(strconv.Atoi) + // func(int) E.Either[error, int] + valPort := E.Eitherize1(validatePort) + + // func(string) E.Either[error, string] + makeUrl := F.Flow3( + atoi, + E.Chain(valPort), + E.Map[error](S.Format[int]("http://localhost:%d")), + ) + + // func(string) (string, error) + makeUrlGo := E.Uneitherize1(makeUrl) + + url, err := makeUrlGo("8080") + if err != nil { + panic(err) + } + fmt.Println(url) + + // Output: + // http://localhost:8080 +} diff --git a/samples/presentation/examples/example_immutability_test.go b/samples/presentation/examples/example_immutability_test.go new file mode 100644 index 0000000..3b69503 --- /dev/null +++ b/samples/presentation/examples/example_immutability_test.go @@ -0,0 +1,156 @@ +// 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 examples + +import ( + "fmt" + "strings" + + F "github.com/IBM/fp-go/function" + N "github.com/IBM/fp-go/number" + L "github.com/IBM/fp-go/optics/lens" +) + +type Person struct { + name string + age int +} + +func (p Person) GetName() string { + return p.name +} + +func (p Person) GetAge() int { + return p.age +} + +func (p Person) SetName(name string) Person { + p.name = name + return p +} + +func (p Person) SetAge(age int) Person { + p.age = age + return p +} + +type Address struct { + city string +} + +func (a Address) GetCity() string { + return a.city +} + +func (a Address) SetCity(city string) Address { + a.city = city + return a +} + +type Client struct { + person Person + address Address +} + +func (c Client) GetPerson() Person { + return c.person +} + +func (c Client) SetPerson(person Person) Client { + c.person = person + return c +} + +func (c Client) GetAddress() Address { + return c.address +} + +func (c Client) SetAddress(address Address) Client { + c.address = address + return c +} + +func MakePerson(name string, age int) Person { + return Person{name, age} +} + +func MakeClient(city string, name string, age int) Client { + return Client{person: Person{name, age}, address: Address{city}} +} + +func Example_immutability_struct() { + p1 := MakePerson("Carsten", 53) + + // func(int) func(Person) Person + setAge := F.Curry2(F.Swap(Person.SetAge)) + + p2 := F.Pipe1( + p1, + setAge(54), + ) + + fmt.Println(p1) + fmt.Println(p2) + + // Output: + // {Carsten 53} + // {Carsten 54} +} + +func Example_immutability_optics() { + + // Lens[Person, int] + ageLens := L.MakeLens(Person.GetAge, Person.SetAge) + // func(Person) Person + incAge := L.Modify[Person](N.Inc[int])(ageLens) + + p1 := MakePerson("Carsten", 53) + p2 := incAge(p1) + + fmt.Println(p1) + fmt.Println(p2) + + // Output: + // {Carsten 53} + // {Carsten 54} +} + +func Example_immutability_lenses() { + + // Lens[Person, string] + nameLens := L.MakeLens(Person.GetName, Person.SetName) + // Lens[Client, Person] + personLens := L.MakeLens(Client.GetPerson, Client.SetPerson) + + // Lens[Client, string] + clientNameLens := F.Pipe1( + personLens, + L.Compose[Client](nameLens), + ) + // func(Client) Client + upperName := L.Modify[Client](strings.ToUpper)(clientNameLens) + + c1 := MakeClient("Böblingen", "Carsten", 53) + + c2 := upperName(c1) + + fmt.Println(c1) + fmt.Println(c2) + + // Output: + // {{Carsten 53} {Böblingen}} + // {{CARSTEN 53} {Böblingen}} +} diff --git a/samples/presentation/introduction.pptx b/samples/presentation/introduction.pptx index bfa3e89..066d357 100644 Binary files a/samples/presentation/introduction.pptx and b/samples/presentation/introduction.pptx differ