mirror of
https://github.com/IBM/fp-go.git
synced 2025-09-05 20:26:12 +02:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
56860425c4 | ||
|
c0b16c675b | ||
|
4b68e66528 | ||
|
5b7e5b153b | ||
|
d43fbeb375 | ||
|
57d507c1ba | ||
|
aa19857127 | ||
|
7766787cc1 |
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
go-version: [ '1.20.x', '1.21.x' ]
|
||||
steps:
|
||||
# full checkout for semantic-release
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up go ${{ matrix.go-version }}
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
steps:
|
||||
# full checkout for semantic-release
|
||||
- name: Full checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
30
array/any.go
Normal file
30
array/any.go
Normal file
@@ -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 array
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/array/generic"
|
||||
)
|
||||
|
||||
// AnyWithIndex tests if any of the elements in the array matches the predicate
|
||||
func AnyWithIndex[A any](pred func(int, A) bool) func([]A) bool {
|
||||
return G.AnyWithIndex[[]A](pred)
|
||||
}
|
||||
|
||||
// Any tests if any of the elements in the array matches the predicate
|
||||
func Any[A any](pred func(A) bool) func([]A) bool {
|
||||
return G.Any[[]A](pred)
|
||||
}
|
30
array/any_test.go
Normal file
30
array/any_test.go
Normal file
@@ -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 array
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAny(t *testing.T) {
|
||||
anyBool := Any(F.Identity[bool])
|
||||
|
||||
assert.True(t, anyBool(From(false, true, false)))
|
||||
assert.False(t, anyBool(From(false, false, false)))
|
||||
}
|
@@ -60,18 +60,6 @@ func MapRef[A, B any](f func(a *A) B) func([]A) []B {
|
||||
return F.Bind2nd(MonadMapRef[A, B], f)
|
||||
}
|
||||
|
||||
func filter[A any](fa []A, pred func(A) bool) []A {
|
||||
var result []A
|
||||
count := len(fa)
|
||||
for i := 0; i < count; i++ {
|
||||
a := fa[i]
|
||||
if pred(a) {
|
||||
result = append(result, a)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func filterRef[A any](fa []A, pred func(a *A) bool) []A {
|
||||
var result []A
|
||||
count := len(fa)
|
||||
@@ -96,23 +84,38 @@ func filterMapRef[A, B any](fa []A, pred func(a *A) bool, f func(a *A) B) []B {
|
||||
return result
|
||||
}
|
||||
|
||||
// Filter returns a new array with all elements from the original array that match a predicate
|
||||
func Filter[A any](pred func(A) bool) func([]A) []A {
|
||||
return F.Bind2nd(filter[A], pred)
|
||||
return G.Filter[[]A](pred)
|
||||
}
|
||||
|
||||
// FilterWithIndex returns a new array with all elements from the original array that match a predicate
|
||||
func FilterWithIndex[A any](pred func(int, A) bool) func([]A) []A {
|
||||
return G.FilterWithIndex[[]A](pred)
|
||||
}
|
||||
|
||||
func FilterRef[A any](pred func(*A) bool) func([]A) []A {
|
||||
return F.Bind2nd(filterRef[A], pred)
|
||||
}
|
||||
|
||||
func MonadFilterMap[A, B any](fa []A, f func(a A) O.Option[B]) []B {
|
||||
func MonadFilterMap[A, B any](fa []A, f func(A) O.Option[B]) []B {
|
||||
return G.MonadFilterMap[[]A, []B](fa, f)
|
||||
}
|
||||
|
||||
// FilterChain maps an array with an iterating function that returns an [O.Option] and it keeps only the Some values discarding the Nones.
|
||||
func FilterMap[A, B any](f func(a A) O.Option[B]) func([]A) []B {
|
||||
func MonadFilterMapWithIndex[A, B any](fa []A, f func(int, A) O.Option[B]) []B {
|
||||
return G.MonadFilterMapWithIndex[[]A, []B](fa, f)
|
||||
}
|
||||
|
||||
// FilterMap maps an array with an iterating function that returns an [O.Option] and it keeps only the Some values discarding the Nones.
|
||||
func FilterMap[A, B any](f func(A) O.Option[B]) func([]A) []B {
|
||||
return G.FilterMap[[]A, []B](f)
|
||||
}
|
||||
|
||||
// FilterMapWithIndex maps an array with an iterating function that returns an [O.Option] and it keeps only the Some values discarding the Nones.
|
||||
func FilterMapWithIndex[A, B any](f func(int, A) O.Option[B]) func([]A) []B {
|
||||
return G.FilterMapWithIndex[[]A, []B](f)
|
||||
}
|
||||
|
||||
// FilterChain maps an array with an iterating function that returns an [O.Option] of an array. It keeps only the Some values discarding the Nones and then flattens the result.
|
||||
func FilterChain[A, B any](f func(A) O.Option[[]B]) func([]A) []B {
|
||||
return G.FilterChain[[]A](f)
|
||||
@@ -134,9 +137,19 @@ func reduceRef[A, B any](fa []A, f func(B, *A) B, initial B) B {
|
||||
}
|
||||
|
||||
func Reduce[A, B any](f func(B, A) B, initial B) func([]A) B {
|
||||
return func(as []A) B {
|
||||
return array.Reduce(as, f, initial)
|
||||
}
|
||||
return G.Reduce[[]A](f, initial)
|
||||
}
|
||||
|
||||
func ReduceWithIndex[A, B any](f func(int, B, A) B, initial B) func([]A) B {
|
||||
return G.ReduceWithIndex[[]A](f, initial)
|
||||
}
|
||||
|
||||
func ReduceRight[A, B any](f func(A, B) B, initial B) func([]A) B {
|
||||
return G.ReduceRight[[]A](f, initial)
|
||||
}
|
||||
|
||||
func ReduceRightWithIndex[A, B any](f func(int, A, B) B, initial B) func([]A) B {
|
||||
return G.ReduceRightWithIndex[[]A](f, initial)
|
||||
}
|
||||
|
||||
func ReduceRef[A, B any](f func(B, *A) B, initial B) func([]A) B {
|
||||
|
@@ -59,6 +59,17 @@ func TestMap(t *testing.T) {
|
||||
assert.Equal(t, dst, []string{"A", "B", "C"})
|
||||
}
|
||||
|
||||
func TestReduceRight(t *testing.T) {
|
||||
values := From("a", "b", "c")
|
||||
f := func(a, acc string) string {
|
||||
return fmt.Sprintf("%s%s", acc, a)
|
||||
}
|
||||
b := ""
|
||||
|
||||
assert.Equal(t, "cba", ReduceRight(f, b)(values))
|
||||
assert.Equal(t, "", ReduceRight(f, b)(Empty[string]()))
|
||||
}
|
||||
|
||||
func TestReduce(t *testing.T) {
|
||||
|
||||
values := MakeBy(101, F.Identity[int])
|
||||
|
77
array/example_any_test.go
Normal file
77
array/example_any_test.go
Normal file
@@ -0,0 +1,77 @@
|
||||
// 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 array
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
func Example_any() {
|
||||
|
||||
pred := func(val int) bool {
|
||||
return val&2 == 0
|
||||
}
|
||||
|
||||
data1 := From(1, 2, 3)
|
||||
|
||||
fmt.Println(Any(pred)(data1))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func Example_any_filter() {
|
||||
|
||||
pred := func(val int) bool {
|
||||
return val&2 == 0
|
||||
}
|
||||
|
||||
data1 := From(1, 2, 3)
|
||||
|
||||
// Any tests if any of the entries in the array matches the condition
|
||||
Any := F.Flow2(
|
||||
Filter(pred),
|
||||
IsNonEmpty[int],
|
||||
)
|
||||
|
||||
fmt.Println(Any(data1))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func Example_any_find() {
|
||||
|
||||
pred := func(val int) bool {
|
||||
return val&2 == 0
|
||||
}
|
||||
|
||||
data1 := From(1, 2, 3)
|
||||
|
||||
// Any tests if any of the entries in the array matches the condition
|
||||
Any := F.Flow2(
|
||||
FindFirst(pred),
|
||||
O.IsSome[int],
|
||||
)
|
||||
|
||||
fmt.Println(Any(data1))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
55
array/example_find_test.go
Normal file
55
array/example_find_test.go
Normal file
@@ -0,0 +1,55 @@
|
||||
// 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 array
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
)
|
||||
|
||||
func Example_find() {
|
||||
|
||||
pred := func(val int) bool {
|
||||
return val&2 == 0
|
||||
}
|
||||
|
||||
data1 := From(1, 2, 3)
|
||||
|
||||
fmt.Println(FindFirst(pred)(data1))
|
||||
|
||||
// Output:
|
||||
// Some[int](1)
|
||||
}
|
||||
|
||||
func Example_find_filter() {
|
||||
|
||||
pred := func(val int) bool {
|
||||
return val&2 == 0
|
||||
}
|
||||
|
||||
data1 := From(1, 2, 3)
|
||||
|
||||
Find := F.Flow2(
|
||||
Filter(pred),
|
||||
Head[int],
|
||||
)
|
||||
|
||||
fmt.Println(Find(data1))
|
||||
|
||||
// Output:
|
||||
// Some[int](1)
|
||||
}
|
61
array/find.go
Normal file
61
array/find.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// 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 array
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/array/generic"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
// FindFirst finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindFirst[A any](pred func(A) bool) func([]A) O.Option[A] {
|
||||
return G.FindFirst[[]A](pred)
|
||||
}
|
||||
|
||||
// FindFirstWithIndex finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindFirstWithIndex[A any](pred func(int, A) bool) func([]A) O.Option[A] {
|
||||
return G.FindFirstWithIndex[[]A](pred)
|
||||
}
|
||||
|
||||
// FindFirstMap finds the first element returned by an [O.Option] based selector function
|
||||
func FindFirstMap[A, B any](sel func(A) O.Option[B]) func([]A) O.Option[B] {
|
||||
return G.FindFirstMap[[]A](sel)
|
||||
}
|
||||
|
||||
// FindFirstMapWithIndex finds the first element returned by an [O.Option] based selector function
|
||||
func FindFirstMapWithIndex[A, B any](sel func(int, A) O.Option[B]) func([]A) O.Option[B] {
|
||||
return G.FindFirstMapWithIndex[[]A](sel)
|
||||
}
|
||||
|
||||
// FindLast finds the Last element which satisfies a predicate (or a refinement) function
|
||||
func FindLast[A any](pred func(A) bool) func([]A) O.Option[A] {
|
||||
return G.FindLast[[]A](pred)
|
||||
}
|
||||
|
||||
// FindLastWithIndex finds the Last element which satisfies a predicate (or a refinement) function
|
||||
func FindLastWithIndex[A any](pred func(int, A) bool) func([]A) O.Option[A] {
|
||||
return G.FindLastWithIndex[[]A](pred)
|
||||
}
|
||||
|
||||
// FindLastMap finds the Last element returned by an [O.Option] based selector function
|
||||
func FindLastMap[A, B any](sel func(A) O.Option[B]) func([]A) O.Option[B] {
|
||||
return G.FindLastMap[[]A](sel)
|
||||
}
|
||||
|
||||
// FindLastMapWithIndex finds the Last element returned by an [O.Option] based selector function
|
||||
func FindLastMapWithIndex[A, B any](sel func(int, A) O.Option[B]) func([]A) O.Option[B] {
|
||||
return G.FindLastMapWithIndex[[]A](sel)
|
||||
}
|
34
array/generic/any.go
Normal file
34
array/generic/any.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// 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"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
// AnyWithIndex tests if any of the elements in the array matches the predicate
|
||||
func AnyWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) bool {
|
||||
return F.Flow2(
|
||||
FindFirstWithIndex[AS](pred),
|
||||
O.IsSome[A],
|
||||
)
|
||||
}
|
||||
|
||||
// Any tests if any of the elements in the array matches the predicate
|
||||
func Any[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) bool {
|
||||
return AnyWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
@@ -29,14 +29,46 @@ func Of[GA ~[]A, A any](value A) GA {
|
||||
return GA{value}
|
||||
}
|
||||
|
||||
func Reduce[GA ~[]A, A, B any](fa GA, f func(B, A) B, initial B) B {
|
||||
func Reduce[GA ~[]A, A, B any](f func(B, A) B, initial B) func(GA) B {
|
||||
return func(as GA) B {
|
||||
return MonadReduce[GA](as, f, initial)
|
||||
}
|
||||
}
|
||||
|
||||
func ReduceWithIndex[GA ~[]A, A, B any](f func(int, B, A) B, initial B) func(GA) B {
|
||||
return func(as GA) B {
|
||||
return MonadReduceWithIndex[GA](as, f, initial)
|
||||
}
|
||||
}
|
||||
|
||||
func ReduceRight[GA ~[]A, A, B any](f func(A, B) B, initial B) func(GA) B {
|
||||
return func(as GA) B {
|
||||
return MonadReduceRight[GA](as, f, initial)
|
||||
}
|
||||
}
|
||||
|
||||
func ReduceRightWithIndex[GA ~[]A, A, B any](f func(int, A, B) B, initial B) func(GA) B {
|
||||
return func(as GA) B {
|
||||
return MonadReduceRightWithIndex[GA](as, f, initial)
|
||||
}
|
||||
}
|
||||
|
||||
func MonadReduce[GA ~[]A, A, B any](fa GA, f func(B, A) B, initial B) B {
|
||||
return array.Reduce(fa, f, initial)
|
||||
}
|
||||
|
||||
func ReduceWithIndex[GA ~[]A, A, B any](fa GA, f func(int, B, A) B, initial B) B {
|
||||
func MonadReduceWithIndex[GA ~[]A, A, B any](fa GA, f func(int, B, A) B, initial B) B {
|
||||
return array.ReduceWithIndex(fa, f, initial)
|
||||
}
|
||||
|
||||
func MonadReduceRight[GA ~[]A, A, B any](fa GA, f func(A, B) B, initial B) B {
|
||||
return array.ReduceRight(fa, f, initial)
|
||||
}
|
||||
|
||||
func MonadReduceRightWithIndex[GA ~[]A, A, B any](fa GA, f func(int, A, B) B, initial B) B {
|
||||
return array.ReduceRightWithIndex(fa, f, initial)
|
||||
}
|
||||
|
||||
// From constructs an array from a set of variadic arguments
|
||||
func From[GA ~[]A, A any](data ...A) GA {
|
||||
return data
|
||||
@@ -122,16 +154,44 @@ func Size[GA ~[]A, A any](as GA) int {
|
||||
return len(as)
|
||||
}
|
||||
|
||||
func filterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(a A) O.Option[B]) GB {
|
||||
func filterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(A) O.Option[B]) GB {
|
||||
return array.Reduce(fa, func(bs GB, a A) GB {
|
||||
return O.MonadFold(f(a), F.Constant(bs), F.Bind1st(Append[GB, B], bs))
|
||||
}, Empty[GB]())
|
||||
}
|
||||
|
||||
func MonadFilterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(a A) O.Option[B]) GB {
|
||||
func filterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(int, A) O.Option[B]) GB {
|
||||
return array.ReduceWithIndex(fa, func(idx int, bs GB, a A) GB {
|
||||
return O.MonadFold(f(idx, a), F.Constant(bs), F.Bind1st(Append[GB, B], bs))
|
||||
}, Empty[GB]())
|
||||
}
|
||||
|
||||
func MonadFilterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(A) O.Option[B]) GB {
|
||||
return filterMap[GA, GB](fa, f)
|
||||
}
|
||||
|
||||
func MonadFilterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(int, A) O.Option[B]) GB {
|
||||
return filterMapWithIndex[GA, GB](fa, f)
|
||||
}
|
||||
|
||||
func filterWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](fa AS, pred PRED) AS {
|
||||
result := make(AS, 0, len(fa))
|
||||
for i, a := range fa {
|
||||
if pred(i, a) {
|
||||
result = append(result, a)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func FilterWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) AS {
|
||||
return F.Bind2nd(filterWithIndex[AS, PRED, A], pred)
|
||||
}
|
||||
|
||||
func Filter[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) AS {
|
||||
return FilterWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
||||
|
||||
func FilterChain[GA ~[]A, GB ~[]B, A, B any](f func(a A) O.Option[GB]) func(GA) GB {
|
||||
return F.Flow2(
|
||||
FilterMap[GA, []GB](f),
|
||||
@@ -143,10 +203,14 @@ func Flatten[GAA ~[]GA, GA ~[]A, A any](mma GAA) GA {
|
||||
return MonadChain(mma, F.Identity[GA])
|
||||
}
|
||||
|
||||
func FilterMap[GA ~[]A, GB ~[]B, A, B any](f func(a A) O.Option[B]) func(GA) GB {
|
||||
func FilterMap[GA ~[]A, GB ~[]B, A, B any](f func(A) O.Option[B]) func(GA) GB {
|
||||
return F.Bind2nd(MonadFilterMap[GA, GB, A, B], f)
|
||||
}
|
||||
|
||||
func FilterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](f func(int, A) O.Option[B]) func(GA) GB {
|
||||
return F.Bind2nd(MonadFilterMapWithIndex[GA, GB, A, B], f)
|
||||
}
|
||||
|
||||
func MonadPartition[GA ~[]A, A any](as GA, pred func(A) bool) tuple.Tuple2[GA, GA] {
|
||||
left := Empty[GA]()
|
||||
right := Empty[GA]()
|
||||
|
97
array/generic/find.go
Normal file
97
array/generic/find.go
Normal file
@@ -0,0 +1,97 @@
|
||||
// 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"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
// FindFirstWithIndex finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindFirstWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) O.Option[A] {
|
||||
none := O.None[A]()
|
||||
return func(as AS) O.Option[A] {
|
||||
for i, a := range as {
|
||||
if pred(i, a) {
|
||||
return O.Some(a)
|
||||
}
|
||||
}
|
||||
return none
|
||||
}
|
||||
}
|
||||
|
||||
// FindFirst finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindFirst[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) O.Option[A] {
|
||||
return FindFirstWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
||||
|
||||
// FindFirstMapWithIndex finds the first element returned by an [O.Option] based selector function
|
||||
func FindFirstMapWithIndex[AS ~[]A, PRED ~func(int, A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
||||
none := O.None[B]()
|
||||
return func(as AS) O.Option[B] {
|
||||
count := len(as)
|
||||
for i := 0; i < count; i++ {
|
||||
out := pred(i, as[i])
|
||||
if O.IsSome(out) {
|
||||
return out
|
||||
}
|
||||
}
|
||||
return none
|
||||
}
|
||||
}
|
||||
|
||||
// FindFirstMap finds the first element returned by an [O.Option] based selector function
|
||||
func FindFirstMap[AS ~[]A, PRED ~func(A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
||||
return FindFirstMapWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
||||
|
||||
// FindLastWithIndex finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindLastWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) O.Option[A] {
|
||||
none := O.None[A]()
|
||||
return func(as AS) O.Option[A] {
|
||||
for i := len(as) - 1; i >= 0; i-- {
|
||||
a := as[i]
|
||||
if pred(i, a) {
|
||||
return O.Some(a)
|
||||
}
|
||||
}
|
||||
return none
|
||||
}
|
||||
}
|
||||
|
||||
// FindLast finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindLast[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) O.Option[A] {
|
||||
return FindLastWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
||||
|
||||
// FindLastMapWithIndex finds the first element returned by an [O.Option] based selector function
|
||||
func FindLastMapWithIndex[AS ~[]A, PRED ~func(int, A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
||||
none := O.None[B]()
|
||||
return func(as AS) O.Option[B] {
|
||||
for i := len(as) - 1; i >= 0; i-- {
|
||||
out := pred(i, as[i])
|
||||
if O.IsSome(out) {
|
||||
return out
|
||||
}
|
||||
}
|
||||
return none
|
||||
}
|
||||
}
|
||||
|
||||
// FindLastMap finds the first element returned by an [O.Option] based selector function
|
||||
func FindLastMap[AS ~[]A, PRED ~func(A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
||||
return FindLastMapWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -46,12 +46,12 @@ func (s Either[E, A]) Format(f fmt.State, c rune) {
|
||||
}
|
||||
}
|
||||
|
||||
// IsLeft tests if the either is a left value. Rather use [Fold] if you need to access the values. Inverse is [IsRight].
|
||||
// IsLeft tests if the [Either] is a left value. Rather use [Fold] if you need to access the values. Inverse is [IsRight].
|
||||
func IsLeft[E, A any](val Either[E, A]) bool {
|
||||
return val.isLeft
|
||||
}
|
||||
|
||||
// IsLeft tests if the either is a right value. Rather use [Fold] if you need to access the values. Inverse is [IsLeft].
|
||||
// IsLeft tests if the [Either] is a right value. Rather use [Fold] if you need to access the values. Inverse is [IsLeft].
|
||||
func IsRight[E, A any](val Either[E, A]) bool {
|
||||
return !val.isLeft
|
||||
}
|
||||
|
25
function/flip.go
Normal file
25
function/flip.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// 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 function
|
||||
|
||||
// Flip reverses the order of parameters of a curried function
|
||||
func Flip[T1, T2, R any](f func(T1) func(T2) R) func(T2) func(T1) R {
|
||||
return func(t2 T2) func(T1) R {
|
||||
return func(t1 T1) R {
|
||||
return f(t1)(t2)
|
||||
}
|
||||
}
|
||||
}
|
36
function/flip_test.go
Normal file
36
function/flip_test.go
Normal file
@@ -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 function
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFlip(t *testing.T) {
|
||||
|
||||
x := Curry2(func(a, b string) string {
|
||||
return fmt.Sprintf("%s:%s", a, b)
|
||||
})
|
||||
|
||||
assert.Equal(t, "a:b", x("a")("b"))
|
||||
|
||||
y := Flip(x)
|
||||
|
||||
assert.Equal(t, "b:a", y("a")("b"))
|
||||
}
|
2
go.mod
2
go.mod
@@ -8,7 +8,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
|
4
go.sum
4
go.sum
@@ -1,5 +1,5 @@
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
|
@@ -51,6 +51,24 @@ func ReduceWithIndex[GA ~[]A, A, B any](fa GA, f func(int, B, A) B, initial B) B
|
||||
return current
|
||||
}
|
||||
|
||||
func ReduceRight[GA ~[]A, A, B any](fa GA, f func(A, B) B, initial B) B {
|
||||
current := initial
|
||||
count := len(fa)
|
||||
for i := count - 1; i >= 0; i-- {
|
||||
current = f(fa[i], current)
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
func ReduceRightWithIndex[GA ~[]A, A, B any](fa GA, f func(int, A, B) B, initial B) B {
|
||||
current := initial
|
||||
count := len(fa)
|
||||
for i := count - 1; i >= 0; i-- {
|
||||
current = f(i, fa[i], current)
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
func Append[GA ~[]A, A any](as GA, a A) GA {
|
||||
return append(as, a)
|
||||
}
|
||||
|
@@ -63,7 +63,7 @@ func TestRetryHttp(t *testing.T) {
|
||||
check := E.Fold(
|
||||
F.Flow2(
|
||||
errors.As[*net.DNSError](),
|
||||
O.Fold(F.Constant(false), F.Constant1[*net.DNSError](true)),
|
||||
O.IsSome[*net.DNSError],
|
||||
),
|
||||
F.Constant1[*PostItem](false),
|
||||
)
|
||||
|
@@ -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)
|
||||
}
|
||||
|
26
iterator/stateless/any.go
Normal file
26
iterator/stateless/any.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// 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 stateless
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/iterator/stateless/generic"
|
||||
)
|
||||
|
||||
// Any returns `true` if any element of the iterable is `true`. If the iterable is empty, return `false`
|
||||
// Similar to the [https://docs.python.org/3/library/functions.html#any] function
|
||||
func Any[U any](pred func(U) bool) func(ma Iterator[U]) bool {
|
||||
return G.Any[Iterator[U]](pred)
|
||||
}
|
38
iterator/stateless/any_test.go
Normal file
38
iterator/stateless/any_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 stateless
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAny(t *testing.T) {
|
||||
|
||||
anyBool := Any(F.Identity[bool])
|
||||
|
||||
i1 := FromArray(A.From(false, true, false))
|
||||
assert.True(t, anyBool(i1))
|
||||
|
||||
i2 := FromArray(A.From(false, false, false))
|
||||
assert.False(t, anyBool(i2))
|
||||
|
||||
i3 := Empty[bool]()
|
||||
assert.False(t, anyBool(i3))
|
||||
}
|
55
iterator/stateless/example_test.go
Normal file
55
iterator/stateless/example_test.go
Normal file
@@ -0,0 +1,55 @@
|
||||
// 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 stateless
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
func Example_any() {
|
||||
// `Any` function that simply returns the boolean identity
|
||||
anyBool := Any(F.Identity[bool])
|
||||
|
||||
fmt.Println(anyBool(FromArray(A.From(true, false, false))))
|
||||
fmt.Println(anyBool(FromArray(A.From(false, false, false))))
|
||||
fmt.Println(anyBool(Empty[bool]()))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func Example_next() {
|
||||
|
||||
seq := MakeBy(F.Identity[int])
|
||||
|
||||
first := seq()
|
||||
|
||||
value := F.Pipe1(
|
||||
first,
|
||||
O.Map(Current[int]),
|
||||
)
|
||||
|
||||
fmt.Println(value)
|
||||
|
||||
// Output:
|
||||
// Some[int](0)
|
||||
}
|
31
iterator/stateless/generic/any.go
Normal file
31
iterator/stateless/generic/any.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// 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"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
// Any returns `true` if any element of the iterable is `true`. If the iterable is empty, return `false`
|
||||
func Any[GU ~func() O.Option[T.Tuple2[GU, U]], FCT ~func(U) bool, U any](pred FCT) func(ma GU) bool {
|
||||
return F.Flow3(
|
||||
Filter[GU](pred),
|
||||
First[GU],
|
||||
O.IsSome[U],
|
||||
)
|
||||
}
|
@@ -41,7 +41,7 @@ func DropWhile[GU ~func() O.Option[T.Tuple2[GU, U]], U any](pred func(U) bool) f
|
||||
return F.Pipe2(
|
||||
t,
|
||||
fromPred,
|
||||
O.Fold(recurse(t.F1), O.Of[T.Tuple2[GU, U]]),
|
||||
O.Fold(recurse(Next(t)), O.Of[T.Tuple2[GU, U]]),
|
||||
)
|
||||
})
|
||||
|
||||
|
@@ -26,6 +26,16 @@ import (
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
// Next returns the iterator for the next element in an iterator `T.Tuple2`
|
||||
func Next[GU ~func() O.Option[T.Tuple2[GU, U]], U any](m T.Tuple2[GU, U]) GU {
|
||||
return T.First(m)
|
||||
}
|
||||
|
||||
// Current returns the current element in an iterator `T.Tuple2`
|
||||
func Current[GU ~func() O.Option[T.Tuple2[GU, U]], U any](m T.Tuple2[GU, U]) U {
|
||||
return T.Second(m)
|
||||
}
|
||||
|
||||
// From constructs an array from a set of variadic arguments
|
||||
func From[GU ~func() O.Option[T.Tuple2[GU, U]], U any](data ...U) GU {
|
||||
return FromArray[GU](data)
|
||||
@@ -56,8 +66,8 @@ func reduce[GU ~func() O.Option[T.Tuple2[GU, U]], U, V any](as GU, f func(V, U)
|
||||
current := initial
|
||||
for ok {
|
||||
// next (with bad side effect)
|
||||
current = f(current, next.F2)
|
||||
next, ok = O.Unwrap(next.F1())
|
||||
current = f(current, Current(next))
|
||||
next, ok = O.Unwrap(Next(next)())
|
||||
}
|
||||
return current
|
||||
}
|
||||
@@ -199,8 +209,8 @@ func FilterMap[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple
|
||||
m = O.Fold(
|
||||
Empty[GV](),
|
||||
func(t T.Tuple2[GU, U]) O.Option[T.Tuple2[GV, V]] {
|
||||
r := recurse(t.F1)
|
||||
return O.MonadFold(f(t.F2), r, F.Flow2(
|
||||
r := recurse(Next(t))
|
||||
return O.MonadFold(f(Current(t)), r, F.Flow2(
|
||||
F.Bind1st(T.MakeTuple2[GV, V], r),
|
||||
O.Some[T.Tuple2[GV, V]],
|
||||
))
|
||||
|
@@ -26,6 +26,16 @@ import (
|
||||
// Iterator represents a stateless, pure way to iterate over a sequence
|
||||
type Iterator[U any] L.Lazy[O.Option[T.Tuple2[Iterator[U], U]]]
|
||||
|
||||
// Next returns the [Iterator] for the next element in an iterator `T.Tuple2`
|
||||
func Next[U any](m T.Tuple2[Iterator[U], U]) Iterator[U] {
|
||||
return G.Next(m)
|
||||
}
|
||||
|
||||
// Current returns the current element in an [Iterator] `T.Tuple2`
|
||||
func Current[U any](m T.Tuple2[Iterator[U], U]) U {
|
||||
return G.Current(m)
|
||||
}
|
||||
|
||||
// Empty returns the empty iterator
|
||||
func Empty[U any]() Iterator[U] {
|
||||
return G.Empty[Iterator[U]]()
|
||||
|
@@ -33,7 +33,7 @@ func MakeMagma[A any](c func(A, A) A) Magma[A] {
|
||||
|
||||
func Reverse[A any](m Magma[A]) Magma[A] {
|
||||
return MakeMagma(func(x A, y A) A {
|
||||
return m.Concat(y, y)
|
||||
return m.Concat(y, x)
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
}
|
||||
|
@@ -6,6 +6,15 @@
|
||||
],
|
||||
"rangeStrategy": "bump",
|
||||
"packageRules": [
|
||||
{
|
||||
"matchManagers": [
|
||||
"gomod"
|
||||
],
|
||||
"matchDepTypes": [
|
||||
"golang"
|
||||
],
|
||||
"enabled": false
|
||||
},
|
||||
{
|
||||
"matchUpdateTypes": [
|
||||
"major",
|
||||
|
@@ -2,6 +2,10 @@
|
||||
|
||||
This folder is meant to contain examples that illustrate how to use the library. I recommend the following reading to get an idea of the underlying concepts. These articles talk about [fp-ts](https://github.com/gcanti/fp-ts) but the concepts are very similar, only syntax differs.
|
||||
|
||||
# Video Introduction
|
||||
|
||||
[](https://www.youtube.com/watch?v=Jif3jL6DRdw "introduction to fp-go")
|
||||
|
||||
### References
|
||||
|
||||
- [Ryan's Blog](https://rlee.dev/practical-guide-to-fp-ts-part-1) - practical introduction into FP concepts
|
||||
|
@@ -107,6 +107,7 @@ func TestHeterogeneousHttpRequests(t *testing.T) {
|
||||
// BenchmarkHeterogeneousHttpRequests shows how to execute multiple HTTP requests in parallel when
|
||||
// the response structure of these requests is different. We use [R.TraverseTuple2] to account for the different types
|
||||
func BenchmarkHeterogeneousHttpRequests(b *testing.B) {
|
||||
|
||||
heterogeneousHttpRequests()(context.Background())
|
||||
for n := 0; n < b.N; n++ {
|
||||
heterogeneousHttpRequests()(context.Background())()
|
||||
}
|
||||
}
|
||||
|
1
samples/presentation/.gitignore
vendored
Normal file
1
samples/presentation/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
~$*
|
123
samples/presentation/benchmarks/http_test.go
Normal file
123
samples/presentation/benchmarks/http_test.go
Normal file
@@ -0,0 +1,123 @@
|
||||
// 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 benchmarks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
HTTP "net/http"
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
R "github.com/IBM/fp-go/context/readerioeither"
|
||||
H "github.com/IBM/fp-go/context/readerioeither/http"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
type PostItem struct {
|
||||
UserId uint `json:"userId"`
|
||||
Id uint `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
|
||||
type CatFact struct {
|
||||
Fact string `json:"fact"`
|
||||
}
|
||||
|
||||
func heterogeneousHttpRequests(count int) R.ReaderIOEither[[]T.Tuple2[PostItem, CatFact]] {
|
||||
// prepare the http client
|
||||
client := H.MakeClient(HTTP.DefaultClient)
|
||||
// readSinglePost sends a GET request and parses the response as [PostItem]
|
||||
readSinglePost := H.ReadJson[PostItem](client)
|
||||
// readSingleCatFact sends a GET request and parses the response as [CatFact]
|
||||
readSingleCatFact := H.ReadJson[CatFact](client)
|
||||
|
||||
single := F.Pipe2(
|
||||
T.MakeTuple2("https://jsonplaceholder.typicode.com/posts/1", "https://catfact.ninja/fact"),
|
||||
T.Map2(H.MakeGetRequest, H.MakeGetRequest),
|
||||
R.TraverseTuple2(
|
||||
readSinglePost,
|
||||
readSingleCatFact,
|
||||
),
|
||||
)
|
||||
|
||||
return F.Pipe1(
|
||||
A.Replicate(count, single),
|
||||
R.SequenceArray[T.Tuple2[PostItem, CatFact]],
|
||||
)
|
||||
}
|
||||
|
||||
func heterogeneousHttpRequestsIdiomatic(count int) ([]T.Tuple2[PostItem, CatFact], error) {
|
||||
// prepare the http client
|
||||
var result []T.Tuple2[PostItem, CatFact]
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
resp, err := HTTP.Get("https://jsonplaceholder.typicode.com/posts/1")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var item PostItem
|
||||
err = json.Unmarshal(body, &item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err = HTTP.Get("https://catfact.ninja/fact")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
body, err = io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var fact CatFact
|
||||
err = json.Unmarshal(body, &item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, T.MakeTuple2(item, fact))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// BenchmarkHeterogeneousHttpRequests shows how to execute multiple HTTP requests in parallel when
|
||||
// the response structure of these requests is different. We use [R.TraverseTuple2] to account for the different types
|
||||
func BenchmarkHeterogeneousHttpRequests(b *testing.B) {
|
||||
|
||||
count := 100
|
||||
var benchResults any
|
||||
|
||||
b.Run("functional", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
benchResults = heterogeneousHttpRequests(count)(context.Background())()
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("idiomatic", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
benchResults, _ = heterogeneousHttpRequestsIdiomatic(count)
|
||||
}
|
||||
})
|
||||
|
||||
globalResult = benchResults
|
||||
}
|
177
samples/presentation/benchmarks/map_test.go
Normal file
177
samples/presentation/benchmarks/map_test.go
Normal file
@@ -0,0 +1,177 @@
|
||||
// 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 benchmarks
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
N "github.com/IBM/fp-go/number"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
var (
|
||||
createStringSet = createRandom(createRandomString(256))(256)
|
||||
createIntDataSet = createRandom(randInt(10000))(256)
|
||||
|
||||
globalResult any
|
||||
)
|
||||
|
||||
func BenchmarkMap(b *testing.B) {
|
||||
|
||||
data := createStringSet()
|
||||
|
||||
var benchResult []string
|
||||
|
||||
b.Run("functional", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
benchResult = F.Pipe1(
|
||||
data,
|
||||
A.Map(strings.ToUpper),
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("idiomatic", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
var result = make([]string, 0, len(data))
|
||||
for _, value := range data {
|
||||
result = append(result, strings.ToUpper(value))
|
||||
}
|
||||
benchResult = result
|
||||
}
|
||||
})
|
||||
|
||||
globalResult = benchResult
|
||||
}
|
||||
|
||||
func isEven(data int) bool {
|
||||
return data%2 == 0
|
||||
}
|
||||
|
||||
func isPrime(data int) bool {
|
||||
return big.NewInt(int64(data)).ProbablyPrime(0)
|
||||
}
|
||||
|
||||
func BenchmarkMapThenFilter(b *testing.B) {
|
||||
|
||||
data := createIntDataSet()
|
||||
var benchResult []int
|
||||
|
||||
b.Run("functional isPrime", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
benchResult = F.Pipe2(
|
||||
data,
|
||||
A.Filter(isPrime),
|
||||
A.Map(N.Div[int](2)),
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("idiomatic isPrime", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
var result []int
|
||||
for _, value := range data {
|
||||
if isPrime(value) {
|
||||
result = append(result, value/2)
|
||||
}
|
||||
}
|
||||
benchResult = result
|
||||
}
|
||||
})
|
||||
b.Run("functional isEven", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
benchResult = F.Pipe2(
|
||||
data,
|
||||
A.Filter(isEven),
|
||||
A.Map(N.Div[int](2)),
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("idiomatic isEven", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
var result []int
|
||||
for _, value := range data {
|
||||
if isEven(value) {
|
||||
result = append(result, value/2)
|
||||
}
|
||||
}
|
||||
benchResult = result
|
||||
}
|
||||
})
|
||||
|
||||
globalResult = benchResult
|
||||
}
|
||||
|
||||
func BenchmarkFilterMap(b *testing.B) {
|
||||
|
||||
data := createIntDataSet()
|
||||
var benchResult []int
|
||||
|
||||
b.Run("functional isPrime", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
benchResult = F.Pipe1(
|
||||
data,
|
||||
A.FilterMap(F.Flow2(
|
||||
O.FromPredicate(isPrime),
|
||||
O.Map(N.Div[int](2)),
|
||||
)),
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("idiomatic isPrime", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
var result []int
|
||||
for _, value := range data {
|
||||
if isPrime(value) {
|
||||
result = append(result, value/2)
|
||||
}
|
||||
}
|
||||
benchResult = result
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("functional isEven", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
benchResult = F.Pipe1(
|
||||
data,
|
||||
A.FilterMap(F.Flow2(
|
||||
O.FromPredicate(isEven),
|
||||
O.Map(N.Div[int](2)),
|
||||
)),
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("idiomatic isEven", func(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
var result []int
|
||||
for _, value := range data {
|
||||
if isEven(value) {
|
||||
result = append(result, value/2)
|
||||
}
|
||||
}
|
||||
benchResult = result
|
||||
}
|
||||
})
|
||||
|
||||
globalResult = benchResult
|
||||
}
|
59
samples/presentation/benchmarks/utils.go
Normal file
59
samples/presentation/benchmarks/utils.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// 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 benchmarks
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
B "github.com/IBM/fp-go/bytes"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
)
|
||||
|
||||
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
|
||||
var (
|
||||
seededRand = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
randChar = F.Pipe2(
|
||||
len(charset),
|
||||
randInt,
|
||||
IO.Map(charAt),
|
||||
)
|
||||
createRandomString = F.Flow3(
|
||||
F.Bind2of2(A.Replicate[IO.IO[byte]])(randChar),
|
||||
IO.SequenceArray[byte],
|
||||
IO.Map(B.ToString),
|
||||
)
|
||||
)
|
||||
|
||||
func createRandom[T any](single IO.IO[T]) func(size int) IO.IO[[]T] {
|
||||
return F.Flow2(
|
||||
F.Bind2of2(A.Replicate[IO.IO[T]])(single),
|
||||
IO.SequenceArray[T],
|
||||
)
|
||||
}
|
||||
|
||||
func charAt(idx int) byte {
|
||||
return charset[idx]
|
||||
}
|
||||
|
||||
func randInt(count int) IO.IO[int] {
|
||||
return func() int {
|
||||
return seededRand.Intn(count)
|
||||
}
|
||||
}
|
BIN
samples/presentation/cover.jpg
Normal file
BIN
samples/presentation/cover.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
1
samples/presentation/examples/data/file1.txt
Normal file
1
samples/presentation/examples/data/file1.txt
Normal file
@@ -0,0 +1 @@
|
||||
Some data
|
3
samples/presentation/examples/data/file2.json
Normal file
3
samples/presentation/examples/data/file2.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"a": 10
|
||||
}
|
70
samples/presentation/examples/example_composition_test.go
Normal file
70
samples/presentation/examples/example_composition_test.go
Normal file
@@ -0,0 +1,70 @@
|
||||
// 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"
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
)
|
||||
|
||||
func Example_composition_pipe() {
|
||||
|
||||
filter := func(i int) bool {
|
||||
return i%2 == 0
|
||||
}
|
||||
|
||||
double := func(i int) int {
|
||||
return i * 2
|
||||
}
|
||||
|
||||
input := []int{1, 2, 3, 4}
|
||||
|
||||
res := F.Pipe2(
|
||||
input,
|
||||
A.Filter(filter),
|
||||
A.Map(double),
|
||||
)
|
||||
|
||||
fmt.Println(res)
|
||||
|
||||
// Output:
|
||||
// [4 8]
|
||||
}
|
||||
|
||||
func Example_composition_flow() {
|
||||
|
||||
filter := func(i int) bool {
|
||||
return i%2 == 0
|
||||
}
|
||||
|
||||
double := func(i int) int {
|
||||
return i * 2
|
||||
}
|
||||
|
||||
input := []int{1, 2, 3, 4}
|
||||
|
||||
filterAndDouble := F.Flow2(
|
||||
A.Filter(filter),
|
||||
A.Map(double),
|
||||
) // func([]int) []int
|
||||
|
||||
fmt.Println(filterAndDouble(input))
|
||||
|
||||
// Output:
|
||||
// [4 8]
|
||||
}
|
103
samples/presentation/examples/example_either_test.go
Normal file
103
samples/presentation/examples/example_either_test.go
Normal file
@@ -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[<nil>, 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
|
||||
}
|
46
samples/presentation/examples/example_generics_test.go
Normal file
46
samples/presentation/examples/example_generics_test.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// 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"
|
||||
|
||||
N "github.com/IBM/fp-go/number"
|
||||
)
|
||||
|
||||
// addInts adds two integers
|
||||
func addInts(left, right int) int {
|
||||
return left + right
|
||||
}
|
||||
|
||||
// addNumbers adds two numbers
|
||||
func addNumbers[T N.Number](left, right T) T {
|
||||
return left + right
|
||||
}
|
||||
|
||||
func Example_generics() {
|
||||
// invoke the non generic version
|
||||
fmt.Println(addInts(1, 2))
|
||||
|
||||
// invoke the generic version
|
||||
fmt.Println(addNumbers(1, 2))
|
||||
fmt.Println(addNumbers(1.0, 2.0))
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 3
|
||||
// 3
|
||||
}
|
34
samples/presentation/examples/example_hof_test.go
Normal file
34
samples/presentation/examples/example_hof_test.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// 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"
|
||||
|
||||
func captureValue[T any](captured T) func() string {
|
||||
return func() string {
|
||||
return fmt.Sprintf("Value: %v", captured)
|
||||
}
|
||||
}
|
||||
|
||||
func Example_closure() {
|
||||
|
||||
hof := captureValue("Carsten") // func() string
|
||||
|
||||
fmt.Println(hof())
|
||||
|
||||
// Output:
|
||||
// Value: Carsten
|
||||
}
|
156
samples/presentation/examples/example_immutability_test.go
Normal file
156
samples/presentation/examples/example_immutability_test.go
Normal file
@@ -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}}
|
||||
}
|
64
samples/presentation/examples/example_map_test.go
Normal file
64
samples/presentation/examples/example_map_test.go
Normal file
@@ -0,0 +1,64 @@
|
||||
// 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"
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
N "github.com/IBM/fp-go/number"
|
||||
)
|
||||
|
||||
func Example_map() {
|
||||
|
||||
f := func(i int) int {
|
||||
return i * 2
|
||||
}
|
||||
|
||||
input := []int{1, 2, 3, 4}
|
||||
|
||||
// idiomatic go
|
||||
res1 := make([]int, 0, len(input))
|
||||
for _, i := range input {
|
||||
res1 = append(res1, f(i))
|
||||
}
|
||||
fmt.Println(res1)
|
||||
|
||||
// map
|
||||
res2 := A.Map(f)(input)
|
||||
fmt.Println(res2)
|
||||
|
||||
// Output:
|
||||
// [2 4 6 8]
|
||||
// [2 4 6 8]
|
||||
}
|
||||
|
||||
func Example_reduce() {
|
||||
|
||||
input := []int{1, 2, 3, 4}
|
||||
|
||||
// reduce
|
||||
red := A.Reduce(N.MonoidSum[int]().Concat, 0)(input)
|
||||
fmt.Println(red)
|
||||
|
||||
// fold
|
||||
fld := A.Fold(N.MonoidSum[int]())(input)
|
||||
fmt.Println(fld)
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
// 10
|
||||
}
|
105
samples/presentation/examples/example_sideeffect_test.go
Normal file
105
samples/presentation/examples/example_sideeffect_test.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 examples
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
B "github.com/IBM/fp-go/bytes"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
"github.com/IBM/fp-go/ioeither/file"
|
||||
J "github.com/IBM/fp-go/json"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
type Sample struct {
|
||||
Value int `json:"a"`
|
||||
}
|
||||
|
||||
func (s Sample) getValue() int {
|
||||
return s.Value
|
||||
}
|
||||
|
||||
func Example_io_flow() {
|
||||
|
||||
// IOE.IOEither[error, string]
|
||||
text := F.Pipe2(
|
||||
"data/file1.txt",
|
||||
file.ReadFile,
|
||||
IOE.Map[error](B.ToString),
|
||||
)
|
||||
|
||||
// IOE.IOEither[error, int]
|
||||
value := F.Pipe3(
|
||||
"data/file2.json",
|
||||
file.ReadFile,
|
||||
IOE.ChainEitherK(J.Unmarshal[Sample]),
|
||||
IOE.Map[error](Sample.getValue),
|
||||
)
|
||||
|
||||
// IOE.IOEither[error, string]
|
||||
result := F.Pipe1(
|
||||
IOE.SequenceT2(text, value),
|
||||
IOE.Map[error](func(res T.Tuple2[string, int]) string {
|
||||
return fmt.Sprintf("Text: %s, Number: %d", res.F1, res.F2)
|
||||
}),
|
||||
)
|
||||
|
||||
fmt.Println(result())
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, string](Text: Some data, Number: 10)
|
||||
|
||||
}
|
||||
|
||||
func io_flow_idiomatic() error {
|
||||
|
||||
// []byte
|
||||
file1AsBytes, err := os.ReadFile("data/file1.txt")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// string
|
||||
text := string(file1AsBytes)
|
||||
|
||||
// []byte
|
||||
file2AsBytes, err := os.ReadFile("data/file2.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var value Sample
|
||||
if err := json.Unmarshal(file2AsBytes, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
// string
|
||||
result := fmt.Sprintf("Text: %s, Number: %d", text, value.Value)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Example_io_flow_idiomatic() {
|
||||
if err := io_flow_idiomatic(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Text: Some data, Number: 10
|
||||
}
|
50
samples/presentation/examples/examples_monad_test.go
Normal file
50
samples/presentation/examples/examples_monad_test.go
Normal file
@@ -0,0 +1,50 @@
|
||||
// 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
|
||||
|
||||
type HKT[T any] struct {
|
||||
}
|
||||
|
||||
// Pointed
|
||||
func Of[A any](A) HKT[A] { return HKT[A]{} }
|
||||
|
||||
// Functor
|
||||
func Map[A, B any](func(A) B) func(HKT[A]) HKT[B] { return func(HKT[A]) HKT[B] { return HKT[B]{} } }
|
||||
func MapTo[A, B any](A) func(HKT[A]) HKT[B] { return func(HKT[A]) HKT[B] { return HKT[B]{} } }
|
||||
|
||||
// Chain
|
||||
func Chain[A, B any](func(A) HKT[B]) func(HKT[A]) HKT[B] {
|
||||
return func(HKT[A]) HKT[B] { return HKT[B]{} }
|
||||
}
|
||||
func ChainTo[A, B any](HKT[B]) func(HKT[A]) HKT[B] {
|
||||
return func(HKT[A]) HKT[B] { return HKT[B]{} }
|
||||
}
|
||||
func ChainFirst[A, B any](func(A) HKT[B]) func(HKT[A]) HKT[A] {
|
||||
return func(HKT[A]) HKT[A] { return HKT[A]{} }
|
||||
}
|
||||
|
||||
// Apply
|
||||
func Ap[A, B any](HKT[A]) func(HKT[func(A) B]) HKT[B] {
|
||||
return func(HKT[func(A) B]) HKT[B] { return HKT[B]{} }
|
||||
}
|
||||
|
||||
// Derived
|
||||
func Flatten[A, B any](HKT[HKT[A]]) HKT[A] {
|
||||
return HKT[A]{}
|
||||
}
|
||||
func Reduce[A, B any](func(B, A) B, B) func(HKT[A]) HKT[B] {
|
||||
return func(HKT[A]) HKT[B] { return HKT[B]{} }
|
||||
}
|
BIN
samples/presentation/introduction.pptx
Normal file
BIN
samples/presentation/introduction.pptx
Normal file
Binary file not shown.
2
test.bat
2
test.bat
@@ -1,3 +1,3 @@
|
||||
@echo off
|
||||
mkdir build 2> NUL
|
||||
gotip test .\... && go1.20.5 test .\... && go test -v -coverprofile build/cover.out -coverpkg=./... -covermode=atomic .\...
|
||||
gotip test .\... && go1.20.11 test .\... && go test -v -coverprofile build/cover.out -coverpkg=./... -covermode=atomic .\...
|
Reference in New Issue
Block a user