1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-11-23 22:14:53 +02:00

fix: initial checkin of v2

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
Dr. Carsten Leue
2025-03-01 23:07:56 +01:00
parent 7a3989989b
commit ddb9e48441
731 changed files with 71516 additions and 0 deletions

30
v2/array/any.go Normal file
View 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/v2/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
v2/array/any_test.go Normal file
View 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/v2/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)))
}

351
v2/array/array.go Normal file
View File

@@ -0,0 +1,351 @@
// 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/v2/array/generic"
EM "github.com/IBM/fp-go/v2/endomorphism"
F "github.com/IBM/fp-go/v2/function"
"github.com/IBM/fp-go/v2/internal/array"
M "github.com/IBM/fp-go/v2/monoid"
O "github.com/IBM/fp-go/v2/option"
"github.com/IBM/fp-go/v2/tuple"
)
// From constructs an array from a set of variadic arguments
func From[A any](data ...A) []A {
return G.From[[]A](data...)
}
// MakeBy returns a `Array` of length `n` with element `i` initialized with `f(i)`.
func MakeBy[F ~func(int) A, A any](n int, f F) []A {
return G.MakeBy[[]A](n, f)
}
// Replicate creates a `Array` containing a value repeated the specified number of times.
func Replicate[A any](n int, a A) []A {
return G.Replicate[[]A](n, a)
}
func MonadMap[A, B any](as []A, f func(a A) B) []B {
return G.MonadMap[[]A, []B](as, f)
}
func MonadMapRef[A, B any](as []A, f func(a *A) B) []B {
count := len(as)
bs := make([]B, count)
for i := count - 1; i >= 0; i-- {
bs[i] = f(&as[i])
}
return bs
}
func MapWithIndex[A, B any](f func(int, A) B) func([]A) []B {
return G.MapWithIndex[[]A, []B](f)
}
func Map[A, B any](f func(a A) B) func([]A) []B {
return G.Map[[]A, []B, A, B](f)
}
func MapRef[A, B any](f func(a *A) B) func([]A) []B {
return F.Bind2nd(MonadMapRef[A, B], f)
}
func filterRef[A any](fa []A, pred func(a *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 filterMapRef[A, B any](fa []A, pred func(a *A) bool, f func(a *A) B) []B {
var result []B
count := len(fa)
for i := 0; i < count; i++ {
a := fa[i]
if pred(&a) {
result = append(result, f(&a))
}
}
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) EM.Endomorphism[[]A] {
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) EM.Endomorphism[[]A] {
return G.FilterWithIndex[[]A](pred)
}
func FilterRef[A any](pred func(*A) bool) EM.Endomorphism[[]A] {
return F.Bind2nd(filterRef[A], pred)
}
func MonadFilterMap[A, B any](fa []A, f func(A) O.Option[B]) []B {
return G.MonadFilterMap[[]A, []B](fa, f)
}
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)
}
func FilterMapRef[A, B any](pred func(a *A) bool, f func(a *A) B) func([]A) []B {
return func(fa []A) []B {
return filterMapRef(fa, pred, f)
}
}
func reduceRef[A, B any](fa []A, f func(B, *A) B, initial B) B {
current := initial
count := len(fa)
for i := 0; i < count; i++ {
current = f(current, &fa[i])
}
return current
}
func Reduce[A, B any](f func(B, A) B, initial B) func([]A) B {
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 {
return func(as []A) B {
return reduceRef(as, f, initial)
}
}
func Append[A any](as []A, a A) []A {
return G.Append(as, a)
}
func IsEmpty[A any](as []A) bool {
return G.IsEmpty(as)
}
func IsNonEmpty[A any](as []A) bool {
return len(as) > 0
}
func Empty[A any]() []A {
return G.Empty[[]A]()
}
func Zero[A any]() []A {
return Empty[A]()
}
// Of constructs a single element array
func Of[A any](a A) []A {
return G.Of[[]A](a)
}
func MonadChain[A, B any](fa []A, f func(a A) []B) []B {
return G.MonadChain[[]A, []B](fa, f)
}
func Chain[A, B any](f func(A) []B) func([]A) []B {
return G.Chain[[]A, []B](f)
}
func MonadAp[B, A any](fab []func(A) B, fa []A) []B {
return G.MonadAp[[]B](fab, fa)
}
func Ap[B, A any](fa []A) func([]func(A) B) []B {
return G.Ap[[]B, []func(A) B](fa)
}
func Match[A, B any](onEmpty func() B, onNonEmpty func([]A) B) func([]A) B {
return G.Match[[]A](onEmpty, onNonEmpty)
}
func MatchLeft[A, B any](onEmpty func() B, onNonEmpty func(A, []A) B) func([]A) B {
return G.MatchLeft[[]A](onEmpty, onNonEmpty)
}
func Tail[A any](as []A) O.Option[[]A] {
return G.Tail(as)
}
func Head[A any](as []A) O.Option[A] {
return G.Head(as)
}
func First[A any](as []A) O.Option[A] {
return G.First(as)
}
func Last[A any](as []A) O.Option[A] {
return G.Last(as)
}
func PrependAll[A any](middle A) EM.Endomorphism[[]A] {
return func(as []A) []A {
count := len(as)
dst := count * 2
result := make([]A, dst)
for i := count - 1; i >= 0; i-- {
dst--
result[dst] = as[i]
dst--
result[dst] = middle
}
return result
}
}
func Intersperse[A any](middle A) EM.Endomorphism[[]A] {
prepend := PrependAll(middle)
return func(as []A) []A {
if IsEmpty(as) {
return as
}
return prepend(as)[1:]
}
}
func Intercalate[A any](m M.Monoid[A]) func(A) func([]A) A {
concatAll := ConcatAll[A](m)
return func(middle A) func([]A) A {
return Match(m.Empty, F.Flow2(Intersperse(middle), concatAll))
}
}
func Flatten[A any](mma [][]A) []A {
return G.Flatten(mma)
}
func Slice[A any](low, high int) func(as []A) []A {
return array.Slice[[]A](low, high)
}
func Lookup[A any](idx int) func([]A) O.Option[A] {
return G.Lookup[[]A](idx)
}
func UpsertAt[A any](a A) EM.Endomorphism[[]A] {
return G.UpsertAt[[]A](a)
}
func Size[A any](as []A) int {
return G.Size(as)
}
func MonadPartition[A any](as []A, pred func(A) bool) tuple.Tuple2[[]A, []A] {
return G.MonadPartition(as, pred)
}
// Partition creates two new arrays out of one, the left result contains the elements
// for which the predicate returns false, the right one those for which the predicate returns true
func Partition[A any](pred func(A) bool) func([]A) tuple.Tuple2[[]A, []A] {
return G.Partition[[]A](pred)
}
// IsNil checks if the array is set to nil
func IsNil[A any](as []A) bool {
return array.IsNil(as)
}
// IsNonNil checks if the array is set to nil
func IsNonNil[A any](as []A) bool {
return array.IsNonNil(as)
}
// ConstNil returns a nil array
func ConstNil[A any]() []A {
return array.ConstNil[[]A]()
}
func SliceRight[A any](start int) EM.Endomorphism[[]A] {
return G.SliceRight[[]A](start)
}
// Copy creates a shallow copy of the array
func Copy[A any](b []A) []A {
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.
func FoldMap[A, B any](m M.Monoid[B]) func(func(A) B) func([]A) B {
return G.FoldMap[[]A](m)
}
// FoldMapWithIndex maps and folds an array. Map the Array passing each value to the iterating function. Then fold the results using the provided Monoid.
func FoldMapWithIndex[A, B any](m M.Monoid[B]) func(func(int, A) B) func([]A) B {
return G.FoldMapWithIndex[[]A](m)
}
// Fold folds the array using the provided Monoid.
func Fold[A any](m M.Monoid[A]) func([]A) A {
return G.Fold[[]A](m)
}
func Push[A any](a A) EM.Endomorphism[[]A] {
return G.Push[EM.Endomorphism[[]A]](a)
}
func MonadFlap[B, A any](fab []func(A) B, a A) []B {
return G.MonadFlap[func(A) B, []func(A) B, []B, A, B](fab, a)
}
func Flap[B, A any](a A) func([]func(A) B) []B {
return G.Flap[func(A) B, []func(A) B, []B, A, B](a)
}
func Prepend[A any](head A) EM.Endomorphism[[]A] {
return G.Prepend[EM.Endomorphism[[]A]](head)
}

205
v2/array/array_test.go Normal file
View File

@@ -0,0 +1,205 @@
// 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"
"strings"
"testing"
F "github.com/IBM/fp-go/v2/function"
"github.com/IBM/fp-go/v2/internal/utils"
O "github.com/IBM/fp-go/v2/option"
S "github.com/IBM/fp-go/v2/string"
T "github.com/IBM/fp-go/v2/tuple"
"github.com/stretchr/testify/assert"
)
func TestMap1(t *testing.T) {
src := []string{"a", "b", "c"}
up := Map(strings.ToUpper)(src)
var up1 = []string{}
for _, s := range src {
up1 = append(up1, strings.ToUpper(s))
}
var up2 = []string{}
for i := range src {
up2 = append(up2, strings.ToUpper(src[i]))
}
assert.Equal(t, up, up1)
assert.Equal(t, up, up2)
}
func TestMap(t *testing.T) {
mapper := Map(utils.Upper)
src := []string{"a", "b", "c"}
dst := mapper(src)
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])
sum := func(val int, current int) int {
return val + current
}
reducer := Reduce(sum, 0)
result := reducer(values)
assert.Equal(t, result, 5050)
}
func TestEmpty(t *testing.T) {
assert.True(t, IsNonEmpty(MakeBy(101, F.Identity[int])))
assert.True(t, IsEmpty([]int{}))
}
func TestAp(t *testing.T) {
assert.Equal(t,
[]int{2, 4, 6, 3, 6, 9},
F.Pipe1(
[]func(int) int{
utils.Double,
utils.Triple,
},
Ap[int, int]([]int{1, 2, 3}),
),
)
}
func TestIntercalate(t *testing.T) {
is := Intercalate(S.Monoid)("-")
assert.Equal(t, "", is(Empty[string]()))
assert.Equal(t, "a", is([]string{"a"}))
assert.Equal(t, "a-b-c", is([]string{"a", "b", "c"}))
assert.Equal(t, "a--c", is([]string{"a", "", "c"}))
assert.Equal(t, "a-b", is([]string{"a", "b"}))
assert.Equal(t, "a-b-c-d", is([]string{"a", "b", "c", "d"}))
}
func TestPrependAll(t *testing.T) {
empty := Empty[int]()
prep := PrependAll(0)
assert.Equal(t, empty, prep(empty))
assert.Equal(t, []int{0, 1, 0, 2, 0, 3}, prep([]int{1, 2, 3}))
assert.Equal(t, []int{0, 1}, prep([]int{1}))
assert.Equal(t, []int{0, 1, 0, 2, 0, 3, 0, 4}, prep([]int{1, 2, 3, 4}))
}
func TestFlatten(t *testing.T) {
assert.Equal(t, []int{1, 2, 3}, Flatten([][]int{{1}, {2}, {3}}))
}
func TestLookup(t *testing.T) {
data := []int{0, 1, 2}
none := O.None[int]()
assert.Equal(t, none, Lookup[int](-1)(data))
assert.Equal(t, none, Lookup[int](10)(data))
assert.Equal(t, O.Some(1), Lookup[int](1)(data))
}
func TestSlice(t *testing.T) {
data := []int{0, 1, 2, 3}
assert.Equal(t, []int{1, 2}, Slice[int](1, 3)(data))
}
func TestFrom(t *testing.T) {
assert.Equal(t, []int{1, 2, 3}, From(1, 2, 3))
}
func TestPartition(t *testing.T) {
pred := func(n int) bool {
return n > 2
}
assert.Equal(t, T.MakeTuple2(Empty[int](), Empty[int]()), Partition(pred)(Empty[int]()))
assert.Equal(t, T.MakeTuple2(From(1), From(3)), Partition(pred)(From(1, 3)))
}
func TestFilterChain(t *testing.T) {
src := From(1, 2, 3)
f := func(i int) O.Option[[]string] {
if i%2 != 0 {
return O.Of(From(fmt.Sprintf("a%d", i), fmt.Sprintf("b%d", i)))
}
return O.None[[]string]()
}
res := FilterChain(f)(src)
assert.Equal(t, From("a1", "b1", "a3", "b3"), res)
}
func TestFilterMap(t *testing.T) {
src := From(1, 2, 3)
f := func(i int) O.Option[string] {
if i%2 != 0 {
return O.Of(fmt.Sprintf("a%d", i))
}
return O.None[string]()
}
res := FilterMap(f)(src)
assert.Equal(t, From("a1", "a3"), res)
}
func TestFoldMap(t *testing.T) {
src := From("a", "b", "c")
fold := FoldMap[string](S.Monoid)(strings.ToUpper)
assert.Equal(t, "ABC", fold(src))
}
func ExampleFoldMap() {
src := From("a", "b", "c")
fold := FoldMap[string](S.Monoid)(strings.ToUpper)
fmt.Println(fold(src))
// Output: ABC
}

66
v2/array/bind.go Normal file
View File

@@ -0,0 +1,66 @@
// 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/v2/array/generic"
)
// Bind creates an empty context of type [S] to be used with the [Bind] operation
func Do[S any](
empty S,
) []S {
return G.Do[[]S, S](empty)
}
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
func Bind[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) []T,
) func([]S1) []S2 {
return G.Bind[[]S1, []S2, []T, S1, S2, T](setter, f)
}
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
func Let[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) T,
) func([]S1) []S2 {
return G.Let[[]S1, []S2, S1, S2, T](setter, f)
}
// LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetTo[S1, S2, T any](
setter func(T) func(S1) S2,
b T,
) func([]S1) []S2 {
return G.LetTo[[]S1, []S2, S1, S2, T](setter, b)
}
// BindTo initializes a new state [S1] from a value [T]
func BindTo[S1, T any](
setter func(T) S1,
) func([]T) []S1 {
return G.BindTo[[]S1, []T, S1, T](setter)
}
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
func ApS[S1, S2, T any](
setter func(T) func(S1) S2,
fa []T,
) func([]S1) []S2 {
return G.ApS[[]S1, []S2, []T, S1, S2, T](setter, fa)
}

56
v2/array/bind_test.go Normal file
View File

@@ -0,0 +1,56 @@
// 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/v2/function"
"github.com/IBM/fp-go/v2/internal/utils"
"github.com/stretchr/testify/assert"
)
func getLastName(s utils.Initial) []string {
return Of("Doe")
}
func getGivenName(s utils.WithLastName) []string {
return Of("John")
}
func TestBind(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
Bind(utils.SetLastName, getLastName),
Bind(utils.SetGivenName, getGivenName),
Map(utils.GetFullName),
)
assert.Equal(t, res, Of("John Doe"))
}
func TestApS(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
ApS(utils.SetLastName, Of("Doe")),
ApS(utils.SetGivenName, Of("John")),
Map(utils.GetFullName),
)
assert.Equal(t, res, Of("John Doe"))
}

40
v2/array/eq.go Normal file
View File

@@ -0,0 +1,40 @@
// 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 (
E "github.com/IBM/fp-go/v2/eq"
)
func equals[T any](left []T, right []T, eq func(T, T) bool) bool {
if len(left) != len(right) {
return false
}
for i, v1 := range left {
v2 := right[i]
if !eq(v1, v2) {
return false
}
}
return true
}
func Eq[T any](e E.Eq[T]) E.Eq[[]T] {
eq := e.Equals
return E.FromEquals(func(left, right []T) bool {
return equals(left, right, eq)
})
}

View 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/v2/function"
O "github.com/IBM/fp-go/v2/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
}

View 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/v2/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)
}

View 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 array
import (
"fmt"
F "github.com/IBM/fp-go/v2/function"
O "github.com/IBM/fp-go/v2/option"
)
// Example_basic adapts examples from [https://github.com/inato/fp-ts-cheatsheet#basic-manipulation]
func Example_basic() {
someArray := From(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) // []int
isEven := func(num int) bool {
return num%2 == 0
}
square := func(num int) int {
return num * num
}
// filter and map
result := F.Pipe2(
someArray,
Filter(isEven),
Map(square),
) // [0 4 16 36 64]
// or in one go with filterMap
resultFilterMap := F.Pipe1(
someArray,
FilterMap(
F.Flow2(O.FromPredicate(isEven), O.Map(square)),
),
)
fmt.Println(result)
fmt.Println(resultFilterMap)
// Output:
// [0 4 16 36 64]
// [0 4 16 36 64]
}

View File

@@ -0,0 +1,92 @@
// 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/v2/function"
I "github.com/IBM/fp-go/v2/number/integer"
O "github.com/IBM/fp-go/v2/option"
"github.com/IBM/fp-go/v2/ord"
S "github.com/IBM/fp-go/v2/string"
)
type user struct {
name string
age O.Option[int]
}
func (user user) GetName() string {
return user.name
}
func (user user) GetAge() O.Option[int] {
return user.age
}
// Example_sort adapts examples from [https://github.com/inato/fp-ts-cheatsheet#sort-elements-with-ord]
func Example_sort() {
strings := From("zyx", "abc", "klm")
sortedStrings := F.Pipe1(
strings,
Sort(S.Ord),
) // => ['abc', 'klm', 'zyx']
// reverse sort
reverseSortedStrings := F.Pipe1(
strings,
Sort(ord.Reverse(S.Ord)),
) // => ['zyx', 'klm', 'abc']
// sort Option
optionalNumbers := From(O.Some(1337), O.None[int](), O.Some(42))
sortedNums := F.Pipe1(
optionalNumbers,
Sort(O.Ord(I.Ord)),
)
// complex object with different rules
byName := F.Pipe1(
S.Ord,
ord.Contramap(user.GetName),
) // ord.Ord[user]
byAge := F.Pipe1(
O.Ord(I.Ord),
ord.Contramap(user.GetAge),
) // ord.Ord[user]
sortedUsers := F.Pipe1(
From(user{name: "a", age: O.Of(30)}, user{name: "d", age: O.Of(10)}, user{name: "c"}, user{name: "b", age: O.Of(10)}),
SortBy(From(byAge, byName)),
)
fmt.Println(sortedStrings)
fmt.Println(reverseSortedStrings)
fmt.Println(sortedNums)
fmt.Println(sortedUsers)
// Output:
// [abc klm zyx]
// [zyx klm abc]
// [None[int] Some[int](42) Some[int](1337)]
// [{c {false 0}} {b {true 10}} {d {true 10}} {a {true 30}}]
}

61
v2/array/find.go Normal file
View 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/v2/array/generic"
O "github.com/IBM/fp-go/v2/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
v2/array/generic/any.go Normal file
View 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/v2/function"
O "github.com/IBM/fp-go/v2/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))
}

352
v2/array/generic/array.go Normal file
View File

@@ -0,0 +1,352 @@
// 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/v2/function"
"github.com/IBM/fp-go/v2/internal/array"
FC "github.com/IBM/fp-go/v2/internal/functor"
M "github.com/IBM/fp-go/v2/monoid"
O "github.com/IBM/fp-go/v2/option"
"github.com/IBM/fp-go/v2/tuple"
)
// Of constructs a single element array
func Of[GA ~[]A, A any](value A) GA {
return GA{value}
}
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 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
}
// MakeBy returns a `Array` of length `n` with element `i` initialized with `f(i)`.
func MakeBy[AS ~[]A, F ~func(int) A, A any](n int, f F) AS {
// sanity check
if n <= 0 {
return Empty[AS]()
}
// run the generator function across the input
as := make(AS, n)
for i := n - 1; i >= 0; i-- {
as[i] = f(i)
}
return as
}
func Replicate[AS ~[]A, A any](n int, a A) AS {
return MakeBy[AS](n, F.Constant1[int](a))
}
func Lookup[GA ~[]A, A any](idx int) func(GA) O.Option[A] {
none := O.None[A]()
if idx < 0 {
return F.Constant1[GA](none)
}
return func(as GA) O.Option[A] {
if idx < len(as) {
return O.Some(as[idx])
}
return none
}
}
func Tail[GA ~[]A, A any](as GA) O.Option[GA] {
if array.IsEmpty(as) {
return O.None[GA]()
}
return O.Some(as[1:])
}
func Head[GA ~[]A, A any](as GA) O.Option[A] {
if array.IsEmpty(as) {
return O.None[A]()
}
return O.Some(as[0])
}
func First[GA ~[]A, A any](as GA) O.Option[A] {
return Head(as)
}
func Last[GA ~[]A, A any](as GA) O.Option[A] {
if array.IsEmpty(as) {
return O.None[A]()
}
return O.Some(as[len(as)-1])
}
func Append[GA ~[]A, A any](as GA, a A) GA {
return array.Append(as, a)
}
func Empty[GA ~[]A, A any]() GA {
return array.Empty[GA]()
}
func UpsertAt[GA ~[]A, A any](a A) func(GA) GA {
return array.UpsertAt[GA](a)
}
func MonadMap[GA ~[]A, GB ~[]B, A, B any](as GA, f func(a A) B) GB {
return array.MonadMap[GA, GB](as, f)
}
func Map[GA ~[]A, GB ~[]B, A, B any](f func(a A) B) func(GA) GB {
return array.Map[GA, GB](f)
}
func MonadMapWithIndex[GA ~[]A, GB ~[]B, A, B any](as GA, f func(int, A) B) GB {
return array.MonadMapWithIndex[GA, GB](as, f)
}
func MapWithIndex[GA ~[]A, GB ~[]B, A, B any](f func(int, A) B) func(GA) GB {
return F.Bind2nd(MonadMapWithIndex[GA, GB, A, B], f)
}
func Size[GA ~[]A, A any](as GA) int {
return len(as)
}
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 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),
Flatten[[]GB],
)
}
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) 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]()
array.Reduce(as, func(c bool, a A) bool {
if pred(a) {
right = append(right, a)
} else {
left = append(left, a)
}
return c
}, true)
// returns the partition
return tuple.MakeTuple2(left, right)
}
func Partition[GA ~[]A, A any](pred func(A) bool) func(GA) tuple.Tuple2[GA, GA] {
return F.Bind2nd(MonadPartition[GA, A], pred)
}
func MonadChain[AS ~[]A, BS ~[]B, A, B any](fa AS, f func(a A) BS) BS {
return array.Reduce(fa, func(bs BS, a A) BS {
return append(bs, f(a)...)
}, Empty[BS]())
}
func Chain[AS ~[]A, BS ~[]B, A, B any](f func(A) BS) func(AS) BS {
return F.Bind2nd(MonadChain[AS, BS, A, B], f)
}
func MonadAp[BS ~[]B, ABS ~[]func(A) B, AS ~[]A, B, A any](fab ABS, fa AS) BS {
return MonadChain(fab, F.Bind1st(MonadMap[AS, BS, A, B], fa))
}
func Ap[BS ~[]B, ABS ~[]func(A) B, AS ~[]A, B, A any](fa AS) func(ABS) BS {
return F.Bind2nd(MonadAp[BS, ABS, AS], fa)
}
func IsEmpty[AS ~[]A, A any](as AS) bool {
return array.IsEmpty(as)
}
func IsNil[GA ~[]A, A any](as GA) bool {
return array.IsNil(as)
}
func IsNonNil[GA ~[]A, A any](as GA) bool {
return array.IsNonNil(as)
}
func Match[AS ~[]A, A, B any](onEmpty func() B, onNonEmpty func(AS) B) func(AS) B {
return func(as AS) B {
if IsEmpty(as) {
return onEmpty()
}
return onNonEmpty(as)
}
}
func MatchLeft[AS ~[]A, A, B any](onEmpty func() B, onNonEmpty func(A, AS) B) func(AS) B {
return func(as AS) B {
if IsEmpty(as) {
return onEmpty()
}
return onNonEmpty(as[0], as[1:])
}
}
func Slice[AS ~[]A, A any](start int, end int) func(AS) AS {
return func(a AS) AS {
return a[start:end]
}
}
func SliceRight[AS ~[]A, A any](start int) func(AS) AS {
return func(a AS) AS {
return a[start:]
}
}
func Copy[AS ~[]A, A any](b AS) AS {
buf := make(AS, len(b))
copy(buf, b)
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 {
return func(f func(A) B) func(AS) B {
return func(as AS) B {
return array.Reduce(as, func(cur B, a A) B {
return m.Concat(cur, f(a))
}, m.Empty())
}
}
}
func FoldMapWithIndex[AS ~[]A, A, B any](m M.Monoid[B]) func(func(int, A) B) func(AS) B {
return func(f func(int, A) B) func(AS) B {
return func(as AS) B {
return array.ReduceWithIndex(as, func(idx int, cur B, a A) B {
return m.Concat(cur, f(idx, a))
}, m.Empty())
}
}
}
func Fold[AS ~[]A, A any](m M.Monoid[A]) func(AS) A {
return func(as AS) A {
return array.Reduce(as, m.Concat, m.Empty())
}
}
func Push[ENDO ~func(GA) GA, GA ~[]A, A any](a A) ENDO {
return F.Bind2nd(array.Push[GA, A], a)
}
func MonadFlap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](fab GFAB, a A) GB {
return FC.MonadFlap(MonadMap[GFAB, GB], fab, a)
}
func Flap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](a A) func(GFAB) GB {
return FC.Flap(Map[GFAB, GB], a)
}
func Prepend[ENDO ~func(AS) AS, AS []A, A any](head A) ENDO {
return array.Prepend[ENDO](head)
}

89
v2/array/generic/bind.go Normal file
View File

@@ -0,0 +1,89 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package generic
import (
A "github.com/IBM/fp-go/v2/internal/apply"
C "github.com/IBM/fp-go/v2/internal/chain"
F "github.com/IBM/fp-go/v2/internal/functor"
)
// Bind creates an empty context of type [S] to be used with the [Bind] operation
func Do[GS ~[]S, S any](
empty S,
) GS {
return Of[GS](empty)
}
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
func Bind[GS1 ~[]S1, GS2 ~[]S2, GT ~[]T, S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) GT,
) func(GS1) GS2 {
return C.Bind(
Chain[GS1, GS2, S1, S2],
Map[GT, GS2, T, S2],
setter,
f,
)
}
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
func Let[GS1 ~[]S1, GS2 ~[]S2, S1, S2, T any](
key func(T) func(S1) S2,
f func(S1) T,
) func(GS1) GS2 {
return F.Let(
Map[GS1, GS2, S1, S2],
key,
f,
)
}
// LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetTo[GS1 ~[]S1, GS2 ~[]S2, S1, S2, B any](
key func(B) func(S1) S2,
b B,
) func(GS1) GS2 {
return F.LetTo(
Map[GS1, GS2, S1, S2],
key,
b,
)
}
// BindTo initializes a new state [S1] from a value [T]
func BindTo[GS1 ~[]S1, GT ~[]T, S1, T any](
setter func(T) S1,
) func(GT) GS1 {
return C.BindTo(
Map[GT, GS1, T, S1],
setter,
)
}
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
func ApS[GS1 ~[]S1, GS2 ~[]S2, GT ~[]T, S1, S2, T any](
setter func(T) func(S1) S2,
fa GT,
) func(GS1) GS2 {
return A.ApS(
Ap[GS2, []func(T) S2, GT, S2, T],
Map[GS1, []func(T) S2, S1, func(T) S2],
setter,
fa,
)
}

97
v2/array/generic/find.go Normal file
View 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/v2/function"
O "github.com/IBM/fp-go/v2/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))
}

43
v2/array/generic/monad.go Normal file
View File

@@ -0,0 +1,43 @@
// Copyright (c) 2024 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 (
"github.com/IBM/fp-go/v2/internal/monad"
)
type arrayMonad[A, B any, GA ~[]A, GB ~[]B, GAB ~[]func(A) B] struct{}
func (o *arrayMonad[A, B, GA, GB, GAB]) Of(a A) GA {
return Of[GA, A](a)
}
func (o *arrayMonad[A, B, GA, GB, GAB]) Map(f func(A) B) func(GA) GB {
return Map[GA, GB, A, B](f)
}
func (o *arrayMonad[A, B, GA, GB, GAB]) Chain(f func(A) GB) func(GA) GB {
return Chain[GA, GB, A, B](f)
}
func (o *arrayMonad[A, B, GA, GB, GAB]) Ap(fa GA) func(GAB) GB {
return Ap[GB, GAB, GA, B, A](fa)
}
// Monad implements the monadic operations for an array
func Monad[A, B any, GA ~[]A, GB ~[]B, GAB ~[]func(A) B]() monad.Monad[A, B, GA, GB, GAB] {
return &arrayMonad[A, B, GA, GB, GAB]{}
}

56
v2/array/generic/sort.go Normal file
View File

@@ -0,0 +1,56 @@
// 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 (
"sort"
F "github.com/IBM/fp-go/v2/function"
O "github.com/IBM/fp-go/v2/ord"
)
// Sort implements a stable sort on the array given the provided ordering
func Sort[GA ~[]T, T any](ord O.Ord[T]) func(ma GA) GA {
return SortByKey[GA](ord, F.Identity[T])
}
// SortByKey implements a stable sort on the array given the provided ordering on an extracted key
func SortByKey[GA ~[]T, K, T any](ord O.Ord[K], f func(T) K) func(ma GA) GA {
return func(ma GA) GA {
// nothing to sort
l := len(ma)
if l < 2 {
return ma
}
// copy
cpy := make(GA, l)
copy(cpy, ma)
sort.Slice(cpy, func(i, j int) bool {
return ord.Compare(f(cpy[i]), f(cpy[j])) < 0
})
return cpy
}
}
// SortBy implements a stable sort on the array given the provided ordering
func SortBy[GA ~[]T, GO ~[]O.Ord[T], T any](ord GO) func(ma GA) GA {
return F.Pipe2(
ord,
Fold[GO](O.Monoid[T]()),
Sort[GA, T],
)
}

32
v2/array/generic/uniq.go Normal file
View File

@@ -0,0 +1,32 @@
package generic
import F "github.com/IBM/fp-go/v2/function"
// StrictUniq converts an array of arbitrary items into an array or unique items
// where uniqueness is determined by the built-in uniqueness constraint
func StrictUniq[AS ~[]A, A comparable](as AS) AS {
return Uniq[AS](F.Identity[A])(as)
}
// uniquePredUnsafe returns a predicate on a map for uniqueness
func uniquePredUnsafe[PRED ~func(A) K, A any, K comparable](f PRED) func(int, A) bool {
lookup := make(map[K]bool)
return func(_ int, a A) bool {
k := f(a)
_, has := lookup[k]
if has {
return false
}
lookup[k] = true
return true
}
}
// Uniq converts an array of arbitrary items into an array or unique items
// where uniqueness is determined based on a key extractor function
func Uniq[AS ~[]A, PRED ~func(A) K, A any, K comparable](f PRED) func(as AS) AS {
return func(as AS) AS {
// we need to create a new predicate for each iteration
return filterWithIndex(as, uniquePredUnsafe(f))
}
}

52
v2/array/generic/zip.go Normal file
View File

@@ -0,0 +1,52 @@
// 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/v2/function"
N "github.com/IBM/fp-go/v2/number"
T "github.com/IBM/fp-go/v2/tuple"
)
// ZipWith applies a function to pairs of elements at the same index in two arrays, collecting the results in a new array. If one
// input array is short, excess elements of the longer array are discarded.
func ZipWith[AS ~[]A, BS ~[]B, CS ~[]C, FCT ~func(A, B) C, A, B, C any](fa AS, fb BS, f FCT) CS {
l := N.Min(len(fa), len(fb))
res := make(CS, l)
for i := l - 1; i >= 0; i-- {
res[i] = f(fa[i], fb[i])
}
return res
}
// Zip takes two arrays and returns an array of corresponding pairs. If one input array is short, excess elements of the
// longer array are discarded
func Zip[AS ~[]A, BS ~[]B, CS ~[]T.Tuple2[A, B], A, B any](fb BS) func(AS) CS {
return F.Bind23of3(ZipWith[AS, BS, CS, func(A, B) T.Tuple2[A, B]])(fb, T.MakeTuple2[A, B])
}
// Unzip is the function is reverse of [Zip]. Takes an array of pairs and return two corresponding arrays
func Unzip[AS ~[]A, BS ~[]B, CS ~[]T.Tuple2[A, B], A, B any](cs CS) T.Tuple2[AS, BS] {
l := len(cs)
as := make(AS, l)
bs := make(BS, l)
for i := l - 1; i >= 0; i-- {
t := cs[i]
as[i] = t.F1
bs[i] = t.F2
}
return T.MakeTuple2(as, bs)
}

24
v2/array/magma.go Normal file
View File

@@ -0,0 +1,24 @@
// 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 (
M "github.com/IBM/fp-go/v2/monoid"
)
func ConcatAll[A any](m M.Monoid[A]) func([]A) A {
return Reduce(m.Concat, m.Empty())
}

36
v2/array/magma_test.go Normal file
View 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 array
import (
"testing"
"github.com/stretchr/testify/assert"
M "github.com/IBM/fp-go/v2/monoid"
)
var subInt = M.MakeMonoid(func(first int, second int) int {
return first - second
}, 0)
func TestConcatAll(t *testing.T) {
var subAll = ConcatAll(subInt)
assert.Equal(t, subAll([]int{1, 2, 3}), -6)
}

26
v2/array/monad.go Normal file
View File

@@ -0,0 +1,26 @@
// Copyright (c) 2024 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/v2/array/generic"
"github.com/IBM/fp-go/v2/internal/monad"
)
// Monad returns the monadic operations for an array
func Monad[A, B any]() monad.Monad[A, B, []A, []B, []func(A) B] {
return G.Monad[A, B, []A, []B, []func(A) B]()
}

63
v2/array/monoid.go Normal file
View File

@@ -0,0 +1,63 @@
// 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 (
"github.com/IBM/fp-go/v2/internal/array"
M "github.com/IBM/fp-go/v2/monoid"
S "github.com/IBM/fp-go/v2/semigroup"
)
func concat[T any](left, right []T) []T {
// some performance checks
ll := len(left)
if ll == 0 {
return right
}
lr := len(right)
if lr == 0 {
return left
}
// need to copy
buf := make([]T, ll+lr)
copy(buf[copy(buf, left):], right)
return buf
}
func Monoid[T any]() M.Monoid[[]T] {
return M.MakeMonoid(concat[T], Empty[T]())
}
func Semigroup[T any]() S.Semigroup[[]T] {
return S.MakeSemigroup(concat[T])
}
func addLen[A any](count int, data []A) int {
return count + len(data)
}
// ConcatAll efficiently concatenates the input arrays into a final array
func ArrayConcatAll[A any](data ...[]A) []A {
// get the full size
count := array.Reduce(data, addLen[A], 0)
buf := make([]A, count)
// copy
array.Reduce(data, func(idx int, seg []A) int {
return idx + copy(buf[idx:], seg)
}, 0)
// returns the final array
return buf
}

26
v2/array/monoid_test.go Normal file
View 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 array
import (
"testing"
M "github.com/IBM/fp-go/v2/monoid/testing"
)
func TestMonoid(t *testing.T) {
M.AssertLaws(t, Monoid[int]())([][]int{{}, {1}, {1, 2}})
}

136
v2/array/nonempty/array.go Normal file
View File

@@ -0,0 +1,136 @@
// 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 nonempty
import (
G "github.com/IBM/fp-go/v2/array/generic"
EM "github.com/IBM/fp-go/v2/endomorphism"
F "github.com/IBM/fp-go/v2/function"
"github.com/IBM/fp-go/v2/internal/array"
S "github.com/IBM/fp-go/v2/semigroup"
)
// NonEmptyArray represents an array with at least one element
type NonEmptyArray[A any] []A
// Of constructs a single element array
func Of[A any](first A) NonEmptyArray[A] {
return G.Of[NonEmptyArray[A]](first)
}
// From constructs a [NonEmptyArray] from a set of variadic arguments
func From[A any](first A, data ...A) NonEmptyArray[A] {
count := len(data)
if count == 0 {
return Of(first)
}
// allocate the requested buffer
buffer := make(NonEmptyArray[A], count+1)
buffer[0] = first
copy(buffer[1:], data)
return buffer
}
func IsEmpty[A any](_ NonEmptyArray[A]) bool {
return false
}
func IsNonEmpty[A any](_ NonEmptyArray[A]) bool {
return true
}
func MonadMap[A, B any](as NonEmptyArray[A], f func(a A) B) NonEmptyArray[B] {
return G.MonadMap[NonEmptyArray[A], NonEmptyArray[B]](as, f)
}
func Map[A, B any](f func(a A) B) func(NonEmptyArray[A]) NonEmptyArray[B] {
return F.Bind2nd(MonadMap[A, B], f)
}
func Reduce[A, B any](f func(B, A) B, initial B) func(NonEmptyArray[A]) B {
return func(as NonEmptyArray[A]) B {
return array.Reduce(as, f, initial)
}
}
func ReduceRight[A, B any](f func(A, B) B, initial B) func(NonEmptyArray[A]) B {
return func(as NonEmptyArray[A]) B {
return array.ReduceRight(as, f, initial)
}
}
func Tail[A any](as NonEmptyArray[A]) []A {
return as[1:]
}
func Head[A any](as NonEmptyArray[A]) A {
return as[0]
}
func First[A any](as NonEmptyArray[A]) A {
return as[0]
}
func Last[A any](as NonEmptyArray[A]) A {
return as[len(as)-1]
}
func Size[A any](as NonEmptyArray[A]) int {
return G.Size(as)
}
func Flatten[A any](mma NonEmptyArray[NonEmptyArray[A]]) NonEmptyArray[A] {
return G.Flatten(mma)
}
func MonadChain[A, B any](fa NonEmptyArray[A], f func(a A) NonEmptyArray[B]) NonEmptyArray[B] {
return G.MonadChain[NonEmptyArray[A], NonEmptyArray[B]](fa, f)
}
func Chain[A, B any](f func(A) NonEmptyArray[B]) func(NonEmptyArray[A]) NonEmptyArray[B] {
return G.Chain[NonEmptyArray[A], NonEmptyArray[B]](f)
}
func MonadAp[B, A any](fab NonEmptyArray[func(A) B], fa NonEmptyArray[A]) NonEmptyArray[B] {
return G.MonadAp[NonEmptyArray[B]](fab, fa)
}
func Ap[B, A any](fa NonEmptyArray[A]) func(NonEmptyArray[func(A) B]) NonEmptyArray[B] {
return G.Ap[NonEmptyArray[B], NonEmptyArray[func(A) B]](fa)
}
// FoldMap maps and folds a [NonEmptyArray]. Map the [NonEmptyArray] passing each value to the iterating function. Then fold the results using the provided [Semigroup].
func FoldMap[A, B any](s S.Semigroup[B]) func(func(A) B) func(NonEmptyArray[A]) B {
return func(f func(A) B) func(NonEmptyArray[A]) B {
return func(as NonEmptyArray[A]) B {
return array.Reduce(Tail(as), func(cur B, a A) B {
return s.Concat(cur, f(a))
}, f(Head(as)))
}
}
}
// Fold folds the [NonEmptyArray] using the provided [Semigroup].
func Fold[A any](s S.Semigroup[A]) func(NonEmptyArray[A]) A {
return func(as NonEmptyArray[A]) A {
return array.Reduce(Tail(as), s.Concat, Head(as))
}
}
// Prepend prepends a single value to an array
func Prepend[A any](head A) EM.Endomorphism[NonEmptyArray[A]] {
return array.Prepend[EM.Endomorphism[NonEmptyArray[A]]](head)
}

58
v2/array/sequence.go Normal file
View File

@@ -0,0 +1,58 @@
// 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 (
F "github.com/IBM/fp-go/v2/function"
O "github.com/IBM/fp-go/v2/option"
)
// We need to pass the members of the applicative explicitly, because golang does neither support higher kinded types nor template methods on structs or interfaces
// HKTA = HKT<A>
// HKTRA = HKT<[]A>
// HKTFRA = HKT<func(A)[]A>
// Sequence takes an `Array` where elements are `HKT<A>` (higher kinded type) and,
// using an applicative of that `HKT`, returns an `HKT` of `[]A`.
// e.g. it can turn an `[]Either[error, string]` into an `Either[error, []string]`.
//
// Sequence requires an `Applicative` of the `HKT` you are targeting, e.g. to turn an
// `[]Either[E, A]` into an `Either[E, []A]`, it needs an
// Applicative` for `Either`, to to turn an `[]Option[A]` into an `Option[ []A]`,
// it needs an `Applicative` for `Option`.
func Sequence[A, HKTA, HKTRA, HKTFRA any](
_of func([]A) HKTRA,
_map func(HKTRA, func([]A) func(A) []A) HKTFRA,
_ap func(HKTFRA, HKTA) HKTRA,
) func([]HKTA) HKTRA {
ca := F.Curry2(Append[A])
return Reduce(func(fas HKTRA, fa HKTA) HKTRA {
return _ap(
_map(fas, ca),
fa,
)
}, _of(Empty[A]()))
}
// ArrayOption returns a function to convert sequence of options into an option of a sequence
func ArrayOption[A any]() func([]O.Option[A]) O.Option[[]A] {
return Sequence(
O.Of[[]A],
O.MonadMap[[]A, func(A) []A],
O.MonadAp[[]A, A],
)
}

31
v2/array/sequence_test.go Normal file
View 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 array
import (
"testing"
"github.com/stretchr/testify/assert"
O "github.com/IBM/fp-go/v2/option"
)
func TestSequenceOption(t *testing.T) {
seq := ArrayOption[int]()
assert.Equal(t, O.Of([]int{1, 3}), seq([]O.Option[int]{O.Of(1), O.Of(3)}))
assert.Equal(t, O.None[[]int](), seq([]O.Option[int]{O.Of(1), O.None[int]()}))
}

36
v2/array/sort.go Normal file
View 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 array
import (
G "github.com/IBM/fp-go/v2/array/generic"
O "github.com/IBM/fp-go/v2/ord"
)
// Sort implements a stable sort on the array given the provided ordering
func Sort[T any](ord O.Ord[T]) func(ma []T) []T {
return G.Sort[[]T](ord)
}
// SortByKey implements a stable sort on the array given the provided ordering on an extracted key
func SortByKey[K, T any](ord O.Ord[K], f func(T) K) func(ma []T) []T {
return G.SortByKey[[]T](ord, f)
}
// SortBy implements a stable sort on the array given the provided ordering
func SortBy[T any](ord []O.Ord[T]) func(ma []T) []T {
return G.SortBy[[]T, []O.Ord[T]](ord)
}

36
v2/array/sort_test.go Normal file
View 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 array
import (
"testing"
O "github.com/IBM/fp-go/v2/ord"
"github.com/stretchr/testify/assert"
)
func TestSort(t *testing.T) {
ordInt := O.FromStrictCompare[int]()
input := []int{2, 1, 3}
res := Sort(ordInt)(input)
assert.Equal(t, []int{1, 2, 3}, res)
assert.Equal(t, []int{2, 1, 3}, input)
}

74
v2/array/testing/laws.go Normal file
View File

@@ -0,0 +1,74 @@
// 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 testing
import (
"testing"
RA "github.com/IBM/fp-go/v2/array"
EQ "github.com/IBM/fp-go/v2/eq"
L "github.com/IBM/fp-go/v2/internal/monad/testing"
)
// AssertLaws asserts the apply monad laws for the array monad
func AssertLaws[A, B, C any](t *testing.T,
eqa EQ.Eq[A],
eqb EQ.Eq[B],
eqc EQ.Eq[C],
ab func(A) B,
bc func(B) C,
) func(a A) bool {
return L.AssertLaws(t,
RA.Eq(eqa),
RA.Eq(eqb),
RA.Eq(eqc),
RA.Of[A],
RA.Of[B],
RA.Of[C],
RA.Of[func(A) A],
RA.Of[func(A) B],
RA.Of[func(B) C],
RA.Of[func(func(A) B) B],
RA.MonadMap[A, A],
RA.MonadMap[A, B],
RA.MonadMap[A, C],
RA.MonadMap[B, C],
RA.MonadMap[func(B) C, func(func(A) B) func(A) C],
RA.MonadChain[A, A],
RA.MonadChain[A, B],
RA.MonadChain[A, C],
RA.MonadChain[B, C],
RA.MonadAp[A, A],
RA.MonadAp[B, A],
RA.MonadAp[C, B],
RA.MonadAp[C, A],
RA.MonadAp[B, func(A) B],
RA.MonadAp[func(A) C, func(A) B],
ab,
bc,
)
}

View File

@@ -0,0 +1,47 @@
// 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 testing
import (
"fmt"
"testing"
EQ "github.com/IBM/fp-go/v2/eq"
"github.com/stretchr/testify/assert"
)
func TestMonadLaws(t *testing.T) {
// some comparison
eqa := EQ.FromStrictEquals[bool]()
eqb := EQ.FromStrictEquals[int]()
eqc := EQ.FromStrictEquals[string]()
ab := func(a bool) int {
if a {
return 1
}
return 0
}
bc := func(b int) string {
return fmt.Sprintf("value %d", b)
}
laws := AssertLaws(t, eqa, eqb, eqc, ab, bc)
assert.True(t, laws(true))
assert.True(t, laws(false))
}

38
v2/array/traverse.go Normal file
View 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 array
import "github.com/IBM/fp-go/v2/internal/array"
func Traverse[A, B, HKTB, HKTAB, HKTRB any](
fof func([]B) HKTRB,
fmap func(func([]B) func(B) []B) func(HKTRB) HKTAB,
fap func(HKTB) func(HKTAB) HKTRB,
f func(A) HKTB) func([]A) HKTRB {
return array.Traverse[[]A](fof, fmap, fap, f)
}
func MonadTraverse[A, B, HKTB, HKTAB, HKTRB any](
fof func([]B) HKTRB,
fmap func(func([]B) func(B) []B) func(HKTRB) HKTAB,
fap func(HKTB) func(HKTAB) HKTRB,
ta []A,
f func(A) HKTB) HKTRB {
return array.MonadTraverse(fof, fmap, fap, ta, f)
}

43
v2/array/traverse_test.go Normal file
View File

@@ -0,0 +1,43 @@
// 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"
O "github.com/IBM/fp-go/v2/option"
"github.com/stretchr/testify/assert"
)
type ArrayType = []int
func TestTraverse(t *testing.T) {
traverse := Traverse(
O.Of[ArrayType],
O.Map[ArrayType, func(int) ArrayType],
O.Ap[ArrayType, int],
func(n int) O.Option[int] {
if n%2 == 0 {
return O.None[int]()
}
return O.Of(n)
})
assert.Equal(t, O.None[[]int](), traverse(ArrayType{1, 2}))
assert.Equal(t, O.Of(ArrayType{1, 3}), traverse(ArrayType{1, 3}))
}

17
v2/array/uniq.go Normal file
View File

@@ -0,0 +1,17 @@
package array
import (
G "github.com/IBM/fp-go/v2/array/generic"
)
// StrictUniq converts an array of arbitrary items into an array or unique items
// where uniqueness is determined by the built-in uniqueness constraint
func StrictUniq[A comparable](as []A) []A {
return G.StrictUniq[[]A](as)
}
// Uniq converts an array of arbitrary items into an array or unique items
// where uniqueness is determined based on a key extractor function
func Uniq[A any, K comparable](f func(A) K) func(as []A) []A {
return G.Uniq[[]A](f)
}

14
v2/array/uniq_test.go Normal file
View File

@@ -0,0 +1,14 @@
package array
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestUniq(t *testing.T) {
data := From(1, 2, 3, 2, 4, 1)
uniq := StrictUniq(data)
assert.Equal(t, From(1, 2, 3, 4), uniq)
}

38
v2/array/zip.go Normal file
View 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 array
import (
G "github.com/IBM/fp-go/v2/array/generic"
T "github.com/IBM/fp-go/v2/tuple"
)
// ZipWith applies a function to pairs of elements at the same index in two arrays, collecting the results in a new array. If one
// input array is short, excess elements of the longer array are discarded.
func ZipWith[FCT ~func(A, B) C, A, B, C any](fa []A, fb []B, f FCT) []C {
return G.ZipWith[[]A, []B, []C, FCT](fa, fb, f)
}
// Zip takes two arrays and returns an array of corresponding pairs. If one input array is short, excess elements of the
// longer array are discarded
func Zip[A, B any](fb []B) func([]A) []T.Tuple2[A, B] {
return G.Zip[[]A, []B, []T.Tuple2[A, B]](fb)
}
// Unzip is the function is reverse of [Zip]. Takes an array of pairs and return two corresponding arrays
func Unzip[A, B any](cs []T.Tuple2[A, B]) T.Tuple2[[]A, []B] {
return G.Unzip[[]A, []B, []T.Tuple2[A, B]](cs)
}

56
v2/array/zip_test.go Normal file
View File

@@ -0,0 +1,56 @@
// 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"
"testing"
T "github.com/IBM/fp-go/v2/tuple"
"github.com/stretchr/testify/assert"
)
func TestZipWith(t *testing.T) {
left := From(1, 2, 3)
right := From("a", "b", "c", "d")
res := ZipWith(left, right, func(l int, r string) string {
return fmt.Sprintf("%s%d", r, l)
})
assert.Equal(t, From("a1", "b2", "c3"), res)
}
func TestZip(t *testing.T) {
left := From(1, 2, 3)
right := From("a", "b", "c", "d")
res := Zip[string](left)(right)
assert.Equal(t, From(T.MakeTuple2("a", 1), T.MakeTuple2("b", 2), T.MakeTuple2("c", 3)), res)
}
func TestUnzip(t *testing.T) {
left := From(1, 2, 3)
right := From("a", "b", "c")
zipped := Zip[string](left)(right)
unzipped := Unzip(zipped)
assert.Equal(t, right, unzipped.F1)
assert.Equal(t, left, unzipped.F2)
}

109
v2/assert/assert_test.go Normal file
View File

@@ -0,0 +1,109 @@
// 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 assert
import (
"fmt"
"testing"
E "github.com/IBM/fp-go/v2/either"
EQ "github.com/IBM/fp-go/v2/eq"
"github.com/stretchr/testify/assert"
)
var (
errTest = fmt.Errorf("test failure")
// Eq is the equal predicate checking if objects are equal
Eq = EQ.FromEquals(assert.ObjectsAreEqual)
)
func wrap1[T any](wrapped func(t assert.TestingT, expected, actual any, msgAndArgs ...any) bool, t *testing.T, expected T) func(actual T) E.Either[error, T] {
return func(actual T) E.Either[error, T] {
ok := wrapped(t, expected, actual)
if ok {
return E.Of[error](actual)
}
return E.Left[T](errTest)
}
}
// NotEqual tests if the expected and the actual values are not equal
func NotEqual[T any](t *testing.T, expected T) func(actual T) E.Either[error, T] {
return wrap1(assert.NotEqual, t, expected)
}
// Equal tests if the expected and the actual values are equal
func Equal[T any](t *testing.T, expected T) func(actual T) E.Either[error, T] {
return wrap1(assert.Equal, t, expected)
}
// Length tests if an array has the expected length
func Length[T any](t *testing.T, expected int) func(actual []T) E.Either[error, []T] {
return func(actual []T) E.Either[error, []T] {
ok := assert.Len(t, actual, expected)
if ok {
return E.Of[error](actual)
}
return E.Left[[]T](errTest)
}
}
// NoError validates that there is no error
func NoError[T any](t *testing.T) func(actual E.Either[error, T]) E.Either[error, T] {
return func(actual E.Either[error, T]) E.Either[error, T] {
return E.MonadFold(actual, func(e error) E.Either[error, T] {
assert.NoError(t, e)
return E.Left[T](e)
}, func(value T) E.Either[error, T] {
assert.NoError(t, nil)
return E.Right[error](value)
})
}
}
// ArrayContains tests if a value is contained in an array
func ArrayContains[T any](t *testing.T, expected T) func(actual []T) E.Either[error, []T] {
return func(actual []T) E.Either[error, []T] {
ok := assert.Contains(t, actual, expected)
if ok {
return E.Of[error](actual)
}
return E.Left[[]T](errTest)
}
}
// ContainsKey tests if a key is contained in a map
func ContainsKey[T any, K comparable](t *testing.T, expected K) func(actual map[K]T) E.Either[error, map[K]T] {
return func(actual map[K]T) E.Either[error, map[K]T] {
ok := assert.Contains(t, actual, expected)
if ok {
return E.Of[error](actual)
}
return E.Left[map[K]T](errTest)
}
}
// NotContainsKey tests if a key is not contained in a map
func NotContainsKey[T any, K comparable](t *testing.T, expected K) func(actual map[K]T) E.Either[error, map[K]T] {
return func(actual map[K]T) E.Either[error, map[K]T] {
ok := assert.NotContains(t, actual, expected)
if ok {
return E.Of[error](actual)
}
return E.Left[map[K]T](errTest)
}
}

59
v2/boolean/boolean.go Normal file
View 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 boolean
import (
EQ "github.com/IBM/fp-go/v2/eq"
M "github.com/IBM/fp-go/v2/monoid"
O "github.com/IBM/fp-go/v2/ord"
)
var (
// MonoidAny is the boolean [M.Monoid] under disjunction
MonoidAny = M.MakeMonoid(
func(l, r bool) bool {
return l || r
},
false,
)
// MonoidAll is the boolean [M.Monoid] under conjuction
MonoidAll = M.MakeMonoid(
func(l, r bool) bool {
return l && r
},
true,
)
// Eq is the equals predicate for boolean
Eq = EQ.FromStrictEquals[bool]()
// Ord is the strict ordering for boolean
Ord = O.MakeOrd(func(l, r bool) int {
if l {
if r {
return 0
}
return +1
}
if r {
return -1
}
return 0
}, func(l, r bool) bool {
return l == r
})
)

64
v2/bounded/bounded.go Normal file
View 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 bounded
import (
O "github.com/IBM/fp-go/v2/ord"
)
type Bounded[T any] interface {
O.Ord[T]
Top() T
Bottom() T
}
type bounded[T any] struct {
c func(x, y T) int
e func(x, y T) bool
t T
b T
}
func (b bounded[T]) Equals(x, y T) bool {
return b.e(x, y)
}
func (b bounded[T]) Compare(x, y T) int {
return b.c(x, y)
}
func (b bounded[T]) Top() T {
return b.t
}
func (b bounded[T]) Bottom() T {
return b.b
}
// MakeBounded creates an instance of a bounded type
func MakeBounded[T any](o O.Ord[T], t, b T) Bounded[T] {
return bounded[T]{c: o.Compare, e: o.Equals, t: t, b: b}
}
// Clamp returns a function that clamps against the bounds defined in the bounded type
func Clamp[T any](b Bounded[T]) func(T) T {
return O.Clamp[T](b)(b.Bottom(), b.Top())
}
// Reverse reverses the ordering and swaps the bounds
func Reverse[T any](b Bounded[T]) Bounded[T] {
return MakeBounded(O.Reverse[T](b), b.Bottom(), b.Top())
}

28
v2/bytes/bytes.go Normal file
View File

@@ -0,0 +1,28 @@
// 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 bytes
func Empty() []byte {
return Monoid.Empty()
}
func ToString(a []byte) string {
return string(a)
}
func Size(as []byte) int {
return len(as)
}

34
v2/bytes/monoid.go Normal file
View 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 bytes
import (
"bytes"
A "github.com/IBM/fp-go/v2/array"
O "github.com/IBM/fp-go/v2/ord"
)
var (
// monoid for byte arrays
Monoid = A.Monoid[byte]()
// ConcatAll concatenates all bytes
ConcatAll = A.ArrayConcatAll[byte]
// Ord implements the default ordering on bytes
Ord = O.MakeOrd(bytes.Compare, bytes.Equal)
)

26
v2/bytes/monoid_test.go Normal file
View 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 bytes
import (
"testing"
M "github.com/IBM/fp-go/v2/monoid/testing"
)
func TestMonoid(t *testing.T) {
M.AssertLaws(t, Monoid)([][]byte{[]byte(""), []byte("a"), []byte("some value")})
}

432
v2/cli/apply.go Normal file
View File

@@ -0,0 +1,432 @@
// 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 cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
C "github.com/urfave/cli/v2"
)
func generateTraverseTuple(f *os.File, i int) {
fmt.Fprintf(f, "\n// TraverseTuple%d is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.\n", i)
fmt.Fprintf(f, "// The function takes a [Tuple%d] of base types and %d functions that transform these based types into higher higher kinded types. It returns a higher kinded type of a [Tuple%d] with the resolved values.\n", i, i, i)
fmt.Fprintf(f, "func TraverseTuple%d[\n", i)
// map as the starting point
fmt.Fprintf(f, " MAP ~func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, " ")
}
fmt.Fprintf(f, "func(T%d)", j+1)
}
fmt.Fprintf(f, " ")
fmt.Fprintf(f, "T.")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") func(HKT_T1)")
if i > 1 {
fmt.Fprintf(f, " HKT_F")
for k := 1; k < i; k++ {
fmt.Fprintf(f, "_T%d", k+1)
}
} else {
fmt.Fprintf(f, " HKT_TUPLE%d", i)
}
fmt.Fprintf(f, ",\n")
// the applicatives
for j := 1; j < i; j++ {
fmt.Fprintf(f, " AP%d ~func(", j)
fmt.Fprintf(f, "HKT_T%d) func(", j+1)
fmt.Fprintf(f, "HKT_F")
for k := j; k < i; k++ {
fmt.Fprintf(f, "_T%d", k+1)
}
fmt.Fprintf(f, ")")
if j+1 < i {
fmt.Fprintf(f, " HKT_F")
for k := j + 1; k < i; k++ {
fmt.Fprintf(f, "_T%d", k+1)
}
} else {
fmt.Fprintf(f, " HKT_TUPLE%d", i)
}
fmt.Fprintf(f, ",\n")
}
for j := 0; j < i; j++ {
fmt.Fprintf(f, " F%d ~func(A%d) HKT_T%d,\n", j+1, j+1, j+1)
}
for j := 0; j < i; j++ {
fmt.Fprintf(f, " A%d, T%d,\n", j+1, j+1)
}
for j := 0; j < i; j++ {
fmt.Fprintf(f, " HKT_T%d, // HKT[T%d]\n", j+1, j+1)
}
for j := 1; j < i; j++ {
fmt.Fprintf(f, " HKT_F")
for k := j; k < i; k++ {
fmt.Fprintf(f, "_T%d", k+1)
}
fmt.Fprintf(f, ", // HKT[")
for k := j; k < i; k++ {
fmt.Fprintf(f, "func(T%d) ", k+1)
}
fmt.Fprintf(f, "T.")
writeTupleType(f, "T", i)
fmt.Fprintf(f, "]\n")
}
fmt.Fprintf(f, " HKT_TUPLE%d any, // HKT[", i)
writeTupleType(f, "T", i)
fmt.Fprintf(f, "]\n")
fmt.Fprintf(f, "](\n")
// the callbacks
fmt.Fprintf(f, " fmap MAP,\n")
for j := 1; j < i; j++ {
fmt.Fprintf(f, " fap%d AP%d,\n", j, j)
}
// the transformer functions
for j := 1; j <= i; j++ {
fmt.Fprintf(f, " f%d F%d,\n", j, j)
}
// the parameters
fmt.Fprintf(f, " t T.Tuple%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "A%d", j+1)
}
fmt.Fprintf(f, "],\n")
fmt.Fprintf(f, ") HKT_TUPLE%d {\n", i)
fmt.Fprintf(f, " return F.Pipe%d(\n", i)
fmt.Fprintf(f, " f1(t.F1),\n")
fmt.Fprintf(f, " fmap(tupleConstructor%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, "]()),\n")
for j := 1; j < i; j++ {
fmt.Fprintf(f, " fap%d(f%d(t.F%d)),\n", j, j+1, j+1)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
}
func generateSequenceTuple(f *os.File, i int) {
fmt.Fprintf(f, "\n// SequenceTuple%d is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.\n", i)
fmt.Fprintf(f, "// The function takes a [Tuple%d] of higher higher kinded types and returns a higher kinded type of a [Tuple%d] with the resolved values.\n", i, i)
fmt.Fprintf(f, "func SequenceTuple%d[\n", i)
// map as the starting point
fmt.Fprintf(f, " MAP ~func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, " ")
}
fmt.Fprintf(f, "func(T%d)", j+1)
}
fmt.Fprintf(f, " ")
fmt.Fprintf(f, "T.")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") func(HKT_T1)")
if i > 1 {
fmt.Fprintf(f, " HKT_F")
for k := 1; k < i; k++ {
fmt.Fprintf(f, "_T%d", k+1)
}
} else {
fmt.Fprintf(f, " HKT_TUPLE%d", i)
}
fmt.Fprintf(f, ",\n")
// the applicatives
for j := 1; j < i; j++ {
fmt.Fprintf(f, " AP%d ~func(", j)
fmt.Fprintf(f, "HKT_T%d) func(", j+1)
fmt.Fprintf(f, "HKT_F")
for k := j; k < i; k++ {
fmt.Fprintf(f, "_T%d", k+1)
}
fmt.Fprintf(f, ")")
if j+1 < i {
fmt.Fprintf(f, " HKT_F")
for k := j + 1; k < i; k++ {
fmt.Fprintf(f, "_T%d", k+1)
}
} else {
fmt.Fprintf(f, " HKT_TUPLE%d", i)
}
fmt.Fprintf(f, ",\n")
}
for j := 0; j < i; j++ {
fmt.Fprintf(f, " T%d,\n", j+1)
}
for j := 0; j < i; j++ {
fmt.Fprintf(f, " HKT_T%d, // HKT[T%d]\n", j+1, j+1)
}
for j := 1; j < i; j++ {
fmt.Fprintf(f, " HKT_F")
for k := j; k < i; k++ {
fmt.Fprintf(f, "_T%d", k+1)
}
fmt.Fprintf(f, ", // HKT[")
for k := j; k < i; k++ {
fmt.Fprintf(f, "func(T%d) ", k+1)
}
fmt.Fprintf(f, "T.")
writeTupleType(f, "T", i)
fmt.Fprintf(f, "]\n")
}
fmt.Fprintf(f, " HKT_TUPLE%d any, // HKT[", i)
writeTupleType(f, "T", i)
fmt.Fprintf(f, "]\n")
fmt.Fprintf(f, "](\n")
// the callbacks
fmt.Fprintf(f, " fmap MAP,\n")
for j := 1; j < i; j++ {
fmt.Fprintf(f, " fap%d AP%d,\n", j, j)
}
// the parameters
fmt.Fprintf(f, " t T.Tuple%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "HKT_T%d", j+1)
}
fmt.Fprintf(f, "],\n")
fmt.Fprintf(f, ") HKT_TUPLE%d {\n", i)
fmt.Fprintf(f, " return F.Pipe%d(\n", i)
fmt.Fprintf(f, " t.F1,\n")
fmt.Fprintf(f, " fmap(tupleConstructor%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, "]()),\n")
for j := 1; j < i; j++ {
fmt.Fprintf(f, " fap%d(t.F%d),\n", j, j+1)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
}
func generateSequenceT(f *os.File, i int) {
fmt.Fprintf(f, "\n// SequenceT%d is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.\n", i)
fmt.Fprintf(f, "// The function takes %d higher higher kinded types and returns a higher kinded type of a [Tuple%d] with the resolved values.\n", i, i)
fmt.Fprintf(f, "func SequenceT%d[\n", i)
// map as the starting point
fmt.Fprintf(f, " MAP ~func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, " ")
}
fmt.Fprintf(f, "func(T%d)", j+1)
}
fmt.Fprintf(f, " ")
fmt.Fprintf(f, "T.")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") func(HKT_T1)")
if i > 1 {
fmt.Fprintf(f, " HKT_F")
for k := 1; k < i; k++ {
fmt.Fprintf(f, "_T%d", k+1)
}
} else {
fmt.Fprintf(f, " HKT_TUPLE%d", i)
}
fmt.Fprintf(f, ",\n")
// the applicatives
for j := 1; j < i; j++ {
fmt.Fprintf(f, " AP%d ~func(", j)
fmt.Fprintf(f, "HKT_T%d) func(", j+1)
fmt.Fprintf(f, "HKT_F")
for k := j; k < i; k++ {
fmt.Fprintf(f, "_T%d", k+1)
}
fmt.Fprintf(f, ")")
if j+1 < i {
fmt.Fprintf(f, " HKT_F")
for k := j + 1; k < i; k++ {
fmt.Fprintf(f, "_T%d", k+1)
}
} else {
fmt.Fprintf(f, " HKT_TUPLE%d", i)
}
fmt.Fprintf(f, ",\n")
}
for j := 0; j < i; j++ {
fmt.Fprintf(f, " T%d,\n", j+1)
}
for j := 0; j < i; j++ {
fmt.Fprintf(f, " HKT_T%d, // HKT[T%d]\n", j+1, j+1)
}
for j := 1; j < i; j++ {
fmt.Fprintf(f, " HKT_F")
for k := j; k < i; k++ {
fmt.Fprintf(f, "_T%d", k+1)
}
fmt.Fprintf(f, ", // HKT[")
for k := j; k < i; k++ {
fmt.Fprintf(f, "func(T%d) ", k+1)
}
fmt.Fprintf(f, "T.")
writeTupleType(f, "T", i)
fmt.Fprintf(f, "]\n")
}
fmt.Fprintf(f, " HKT_TUPLE%d any, // HKT[", i)
writeTupleType(f, "T", i)
fmt.Fprintf(f, "]\n")
fmt.Fprintf(f, "](\n")
// the callbacks
fmt.Fprintf(f, " fmap MAP,\n")
for j := 1; j < i; j++ {
fmt.Fprintf(f, " fap%d AP%d,\n", j, j)
}
// the parameters
for j := 0; j < i; j++ {
fmt.Fprintf(f, " t%d HKT_T%d,\n", j+1, j+1)
}
fmt.Fprintf(f, ") HKT_TUPLE%d {\n", i)
fmt.Fprintf(f, " return F.Pipe%d(\n", i)
fmt.Fprintf(f, " t1,\n")
fmt.Fprintf(f, " fmap(tupleConstructor%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, "]()),\n")
for j := 1; j < i; j++ {
fmt.Fprintf(f, " fap%d(t%d),\n", j, j+1)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
}
func generateTupleConstructor(f *os.File, i int) {
// Create the optionize version
fmt.Fprintf(f, "\n// tupleConstructor%d returns a curried version of [T.MakeTuple%d]\n", i, i)
fmt.Fprintf(f, "func tupleConstructor%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, " any]()")
for j := 0; j < i; j++ {
fmt.Fprintf(f, " func(T%d)", j+1)
}
fmt.Fprintf(f, " T.Tuple%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, "] {\n")
fmt.Fprintf(f, " return F.Curry%d(T.MakeTuple%d[", i, i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, "])\n")
fmt.Fprintf(f, "}\n")
}
func generateApplyHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)
// print out some helpers
fmt.Fprintf(f, `
import (
F "github.com/IBM/fp-go/v2/function"
T "github.com/IBM/fp-go/v2/tuple"
)
`)
for i := 1; i <= count; i++ {
// tuple constructor
generateTupleConstructor(f, i)
// sequenceT
generateSequenceT(f, i)
// sequenceTuple
generateSequenceTuple(f, i)
// traverseTuple
generateTraverseTuple(f, i)
}
return nil
}
func ApplyCommand() *C.Command {
return &C.Command{
Name: "apply",
Usage: "generate code for the sequence operations of apply",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateApplyHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

294
v2/cli/bind.go Normal file
View File

@@ -0,0 +1,294 @@
// 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 cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
C "github.com/urfave/cli/v2"
)
func createCombinations(n int, all, prev []int) [][]int {
l := len(prev)
if l == n {
return [][]int{prev}
}
var res [][]int
for idx, val := range all {
cpy := make([]int, l+1)
copy(cpy, prev)
cpy[l] = val
res = append(res, createCombinations(n, all[idx+1:], cpy)...)
}
return res
}
func remaining(comb []int, total int) []int {
var res []int
mp := make(map[int]int)
for _, idx := range comb {
mp[idx] = idx
}
for i := 1; i <= total; i++ {
_, ok := mp[i]
if !ok {
res = append(res, i)
}
}
return res
}
func generateCombSingleBind(f *os.File, comb [][]int, total int) {
for _, c := range comb {
// remaining indexes
rem := remaining(c, total)
// bind function
fmt.Fprintf(f, "\n// Bind")
for _, idx := range c {
fmt.Fprintf(f, "%d", idx)
}
fmt.Fprintf(f, "of%d takes a function with %d parameters and returns a new function with %d parameters that will bind these parameters to the positions [", total, total, len(c))
for i, idx := range c {
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "%d", idx)
}
fmt.Fprintf(f, "] of the original function.\n// The return value of is a function with the remaining %d parameters at positions [", len(rem))
for i, idx := range rem {
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "%d", idx)
}
fmt.Fprintf(f, "] of the original function.\n")
fmt.Fprintf(f, "func Bind")
for _, idx := range c {
fmt.Fprintf(f, "%d", idx)
}
fmt.Fprintf(f, "of%d[F ~func(", total)
for i := 0; i < total; i++ {
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", i+1)
}
fmt.Fprintf(f, ") R")
for i := 0; i < total; i++ {
fmt.Fprintf(f, ", T%d", i+1)
}
fmt.Fprintf(f, ", R any](f F) func(")
for i, idx := range c {
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", idx)
}
fmt.Fprintf(f, ") func(")
for i, idx := range rem {
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", idx)
}
fmt.Fprintf(f, ") R {\n")
fmt.Fprintf(f, " return func(")
for i, idx := range c {
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d T%d", idx, idx)
}
fmt.Fprintf(f, ") func(")
for i, idx := range rem {
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", idx)
}
fmt.Fprintf(f, ") R {\n")
fmt.Fprintf(f, " return func(")
for i, idx := range rem {
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d T%d", idx, idx)
}
fmt.Fprintf(f, ") R {\n")
fmt.Fprintf(f, " return f(")
for i := 1; i <= total; i++ {
if i > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", i)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, "}\n")
// ignore function
fmt.Fprintf(f, "\n// Ignore")
for _, idx := range c {
fmt.Fprintf(f, "%d", idx)
}
fmt.Fprintf(f, "of%d takes a function with %d parameters and returns a new function with %d parameters that will ignore the values at positions [", total, len(rem), total)
for i, idx := range c {
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "%d", idx)
}
fmt.Fprintf(f, "] and pass the remaining %d parameters to the original function\n", len(rem))
fmt.Fprintf(f, "func Ignore")
for _, idx := range c {
fmt.Fprintf(f, "%d", idx)
}
fmt.Fprintf(f, "of%d[", total)
// start with the undefined parameters
for i, idx := range c {
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", idx)
}
if len(c) > 0 {
fmt.Fprintf(f, " any, ")
}
fmt.Fprintf(f, "F ~func(")
for i, idx := range rem {
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", idx)
}
fmt.Fprintf(f, ") R")
for _, idx := range rem {
fmt.Fprintf(f, ", T%d", idx)
}
fmt.Fprintf(f, ", R any](f F) func(")
for i := 0; i < total; i++ {
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", i+1)
}
fmt.Fprintf(f, ") R {\n")
fmt.Fprintf(f, " return func(")
for i := 0; i < total; i++ {
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d T%d", i+1, i+1)
}
fmt.Fprintf(f, ") R {\n")
fmt.Fprintf(f, " return f(")
for i, idx := range rem {
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", idx)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, "}\n")
}
}
func generateSingleBind(f *os.File, total int) {
fmt.Fprintf(f, "// Combinations for a total of %d arguments\n", total)
// construct the indexes
all := make([]int, total)
for i := 0; i < total; i++ {
all[i] = i + 1
}
// for all permutations of a certain length
for j := 0; j < total; j++ {
// get combinations of that size
comb := createCombinations(j+1, all, []int{})
generateCombSingleBind(f, comb, total)
}
}
func generateBind(f *os.File, i int) {
for j := 1; j < i; j++ {
generateSingleBind(f, j)
}
}
func generateBindHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n", pkg)
generateBind(f, count)
return nil
}
func BindCommand() *C.Command {
return &C.Command{
Name: "bind",
Usage: "generate code for binder functions etc",
Description: "Code generation for bind, etc",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateBindHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

39
v2/cli/commands.go Normal file
View File

@@ -0,0 +1,39 @@
// 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 cli
import (
C "github.com/urfave/cli/v2"
)
func Commands() []*C.Command {
return []*C.Command{
PipeCommand(),
IdentityCommand(),
OptionCommand(),
EitherCommand(),
TupleCommand(),
BindCommand(),
ApplyCommand(),
ContextReaderIOEitherCommand(),
ReaderIOEitherCommand(),
ReaderCommand(),
IOEitherCommand(),
IOCommand(),
IOOptionCommand(),
DICommand(),
}
}

39
v2/cli/common.go Normal file
View File

@@ -0,0 +1,39 @@
// 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 cli
import (
C "github.com/urfave/cli/v2"
)
const (
keyFilename = "filename"
keyCount = "count"
)
var (
flagFilename = &C.StringFlag{
Name: keyFilename,
Value: "gen.go",
Usage: "Name of the generated file",
}
flagCount = &C.IntFlag{
Name: keyCount,
Value: 20,
Usage: "Number of variations to create",
}
)

View File

@@ -0,0 +1,525 @@
// 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 cli
import (
"fmt"
"log"
"os"
"path/filepath"
"strings"
C "github.com/urfave/cli/v2"
)
func generateNestedCallbacks(i, total int) string {
var buf strings.Builder
for j := i; j < total; j++ {
if j > i {
buf.WriteString(" ")
}
buf.WriteString(fmt.Sprintf("func(T%d)", j+1))
}
if i > 0 {
buf.WriteString(" ")
}
buf.WriteString(tupleType("T")(total))
return buf.String()
}
func generateContextReaderIOEitherTraverseTuple(suffix string) func(f, fg *os.File, i int) {
return func(f, fg *os.File, i int) {
// tupleT type
tupleT := tupleType("T")(i)
tupleA := tupleType("A")(i)
// non-generic version
// generic version
fmt.Fprintf(f, "\n// Traverse%sTuple%d converts a [T.Tuple%d] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple%d].\n", suffix, i, i, i)
fmt.Fprintf(f, "func Traverse%sTuple%d[", suffix, i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "F%d ~func(A%d) ReaderIOEither[T%d]", j+1, j+1, j+1)
}
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", A%d, T%d", j+1, j+1)
}
fmt.Fprintf(f, " any](")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "f%d F%d", j+1, j+1)
}
fmt.Fprintf(f, ") func(%s) ReaderIOEither[%s] {\n", tupleA, tupleT)
fmt.Fprintf(f, " return G.Traverse%sTuple%d[ReaderIOEither[%s]](", suffix, i, tupleT)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "f%d", j+1)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
// generic version
fmt.Fprintf(fg, "\n// Traverse%sTuple%d converts a [T.Tuple%d] of readers into a reader of a [T.Tuple%d].\n", suffix, i, i, i)
fmt.Fprintf(fg, "func Traverse%sTuple%d[\n", suffix, i)
fmt.Fprintf(fg, " GR_TUPLE%d ~func(context.Context) GIO_TUPLE%d,\n", i, i)
// the transformation functions
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " F%d ~func(A%d) GR_T%d,\n", j+1, j+1, j+1)
}
// the readers
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " GR_T%d ~func(context.Context) GIO_T%d,\n", j+1, j+1)
}
// the tuples
fmt.Fprintf(fg, " GIO_TUPLE%d ~func() E.Either[error, %s],\n", i, tupleT)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " GIO_T%d ~func() E.Either[error, T%d],\n", j+1, j+1)
}
// input and result parameters
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " A%d,\n", j+1)
fmt.Fprintf(fg, " T%d", j+1)
if j < i-1 {
fmt.Fprintf(fg, ",\n")
}
}
fmt.Fprintf(fg, " any](")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "f%d F%d", j+1, j+1)
}
fmt.Fprintf(fg, ") func(%s) GR_TUPLE%d {\n", tupleA, i)
fmt.Fprintf(fg, " return func(t %s) GR_TUPLE%d {\n", tupleA, i)
fmt.Fprintf(fg, " return A.TraverseTuple%d(\n", i)
// map call
var cr string
if i > 1 {
cb := generateNestedCallbacks(1, i)
cio := fmt.Sprintf("func() E.Either[error, %s]", cb)
cr = fmt.Sprintf("func(context.Context) %s", cio)
} else {
cr = fmt.Sprintf("GR_TUPLE%d", i)
}
fmt.Fprintf(fg, " Map[GR_T%d, %s, GIO_T%d],\n", 1, cr, 1)
// the apply calls
for j := 1; j < i; j++ {
if j < i-1 {
cb := generateNestedCallbacks(j+1, i)
cio := fmt.Sprintf("func() E.Either[error, %s]", cb)
cr = fmt.Sprintf("func(context.Context) %s", cio)
} else {
cr = fmt.Sprintf("GR_TUPLE%d", i)
}
fmt.Fprintf(fg, " Ap%s[%s, func(context.Context) func() E.Either[error, %s], GR_T%d],\n", suffix, cr, generateNestedCallbacks(j, i), j+1)
}
// function parameters
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " f%d,\n", j+1)
}
// raw parameters
fmt.Fprintf(fg, " t,\n")
fmt.Fprintf(fg, " )\n")
fmt.Fprintf(fg, " }\n")
fmt.Fprintf(fg, "}\n")
}
}
func generateContextReaderIOEitherSequenceTuple(suffix string) func(f, fg *os.File, i int) {
return func(f, fg *os.File, i int) {
// tuple type
tuple := tupleType("T")(i)
// non-generic version
// generic version
fmt.Fprintf(f, "\n// Sequence%sTuple%d converts a [T.Tuple%d] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple%d].\n", suffix, i, i, i)
fmt.Fprintf(f, "func Sequence%sTuple%d[", suffix, i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, " any](t T.Tuple%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "ReaderIOEither[T%d]", j+1)
}
fmt.Fprintf(f, "]) ReaderIOEither[%s] {\n", tuple)
fmt.Fprintf(f, " return G.Sequence%sTuple%d[ReaderIOEither[%s]](t)\n", suffix, i, tuple)
fmt.Fprintf(f, "}\n")
// generic version
fmt.Fprintf(fg, "\n// Sequence%sTuple%d converts a [T.Tuple%d] of readers into a reader of a [T.Tuple%d].\n", suffix, i, i, i)
fmt.Fprintf(fg, "func Sequence%sTuple%d[\n", suffix, i)
fmt.Fprintf(fg, " GR_TUPLE%d ~func(context.Context) GIO_TUPLE%d,\n", i, i)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " GR_T%d ~func(context.Context) GIO_T%d,\n", j+1, j+1)
}
fmt.Fprintf(fg, " GIO_TUPLE%d ~func() E.Either[error, %s],\n", i, tuple)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " GIO_T%d ~func() E.Either[error, T%d],\n", j+1, j+1)
}
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " T%d", j+1)
if j < i-1 {
fmt.Fprintf(fg, ",\n")
}
}
fmt.Fprintf(fg, " any](t T.Tuple%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "GR_T%d", j+1)
}
fmt.Fprintf(fg, "]) GR_TUPLE%d {\n", i)
fmt.Fprintf(fg, " return A.SequenceTuple%d(\n", i)
// map call
var cr string
if i > 1 {
cb := generateNestedCallbacks(1, i)
cio := fmt.Sprintf("func() E.Either[error, %s]", cb)
cr = fmt.Sprintf("func(context.Context) %s", cio)
} else {
cr = fmt.Sprintf("GR_TUPLE%d", i)
}
fmt.Fprintf(fg, " Map[GR_T%d, %s, GIO_T%d],\n", 1, cr, 1)
// the apply calls
for j := 1; j < i; j++ {
if j < i-1 {
cb := generateNestedCallbacks(j+1, i)
cio := fmt.Sprintf("func() E.Either[error, %s]", cb)
cr = fmt.Sprintf("func(context.Context) %s", cio)
} else {
cr = fmt.Sprintf("GR_TUPLE%d", i)
}
fmt.Fprintf(fg, " Ap%s[%s, func(context.Context) func() E.Either[error, %s], GR_T%d],\n", suffix, cr, generateNestedCallbacks(j, i), j+1)
}
// raw parameters
fmt.Fprintf(fg, " t,\n")
fmt.Fprintf(fg, " )\n")
fmt.Fprintf(fg, "}\n")
}
}
func generateContextReaderIOEitherSequenceT(suffix string) func(f, fg *os.File, i int) {
return func(f, fg *os.File, i int) {
// tuple type
tuple := tupleType("T")(i)
// non-generic version
// generic version
fmt.Fprintf(f, "\n// Sequence%sT%d converts %d [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple%d].\n", suffix, i, i, i)
fmt.Fprintf(f, "func Sequence%sT%d[", suffix, i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, " any](")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d ReaderIOEither[T%d]", j+1, j+1)
}
fmt.Fprintf(f, ") ReaderIOEither[%s] {\n", tuple)
fmt.Fprintf(f, " return G.Sequence%sT%d[ReaderIOEither[%s]](", suffix, i, tuple)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j+1)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
// generic version
fmt.Fprintf(fg, "\n// Sequence%sT%d converts %d readers into a reader of a [T.Tuple%d].\n", suffix, i, i, i)
fmt.Fprintf(fg, "func Sequence%sT%d[\n", suffix, i)
fmt.Fprintf(fg, " GR_TUPLE%d ~func(context.Context) GIO_TUPLE%d,\n", i, i)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " GR_T%d ~func(context.Context) GIO_T%d,\n", j+1, j+1)
}
fmt.Fprintf(fg, " GIO_TUPLE%d ~func() E.Either[error, %s],\n", i, tuple)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " GIO_T%d ~func() E.Either[error, T%d],\n", j+1, j+1)
}
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " T%d", j+1)
if j < i-1 {
fmt.Fprintf(fg, ",\n")
}
}
fmt.Fprintf(fg, " any](\n")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " t%d GR_T%d,\n", j+1, j+1)
}
fmt.Fprintf(fg, ") GR_TUPLE%d {\n", i)
fmt.Fprintf(fg, " return A.SequenceT%d(\n", i)
// map call
var cr string
if i > 1 {
cb := generateNestedCallbacks(1, i)
cio := fmt.Sprintf("func() E.Either[error, %s]", cb)
cr = fmt.Sprintf("func(context.Context) %s", cio)
} else {
cr = fmt.Sprintf("GR_TUPLE%d", i)
}
fmt.Fprintf(fg, " Map[GR_T%d, %s, GIO_T%d],\n", 1, cr, 1)
// the apply calls
for j := 1; j < i; j++ {
if j < i-1 {
cb := generateNestedCallbacks(j+1, i)
cio := fmt.Sprintf("func() E.Either[error, %s]", cb)
cr = fmt.Sprintf("func(context.Context) %s", cio)
} else {
cr = fmt.Sprintf("GR_TUPLE%d", i)
}
fmt.Fprintf(fg, " Ap%s[%s, func(context.Context) func() E.Either[error, %s], GR_T%d],\n", suffix, cr, generateNestedCallbacks(j, i), j+1)
}
// raw parameters
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " t%d,\n", j+1)
}
fmt.Fprintf(fg, " )\n")
fmt.Fprintf(fg, "}\n")
}
}
func generateContextReaderIOEitherEitherize(f, fg *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [ReaderIOEither[R]]\n// The inverse function is [Uneitherize%d]\n", i, i, i, i)
fmt.Fprintf(f, "func Eitherize%d[F ~func(context.Context", i)
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ") (R, error)")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") ReaderIOEither[R] {\n")
fmt.Fprintf(f, " return G.Eitherize%d[ReaderIOEither[R]](f)\n", i)
fmt.Fprintln(f, "}")
// generic version
fmt.Fprintf(fg, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [GRA]\n// The inverse function is [Uneitherize%d]\n", i, i, i, i)
fmt.Fprintf(fg, "func Eitherize%d[GRA ~func(context.Context) GIOA, F ~func(context.Context", i)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ") (R, error), GIOA ~func() E.Either[error, R]")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ", R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j)
}
fmt.Fprintf(fg, ") GRA {\n")
fmt.Fprintf(fg, " return RE.Eitherize%d[GRA](f)\n", i)
fmt.Fprintln(fg, "}")
}
func generateContextReaderIOEitherUneitherize(f, fg *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// Uneitherize%d converts a function with %d parameters returning a [ReaderIOEither[R]] into a function with %d parameters returning a tuple.\n// The first parameter is considered to be the [context.Context].\n", i, i+1, i)
fmt.Fprintf(f, "func Uneitherize%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") ReaderIOEither[R]")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", R any](f F) func(context.Context")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ") (R, error) {\n")
fmt.Fprintf(f, " return G.Uneitherize%d[ReaderIOEither[R]", i)
fmt.Fprintf(f, ", func(context.Context")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ")(R, error)](f)\n")
fmt.Fprintln(f, "}")
// generic version
fmt.Fprintf(fg, "\n// Uneitherize%d converts a function with %d parameters returning a [GRA] into a function with %d parameters returning a tuple.\n// The first parameter is considered to be the [context.Context].\n", i, i, i)
fmt.Fprintf(fg, "func Uneitherize%d[GRA ~func(context.Context) GIOA, F ~func(context.Context", i)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ") (R, error), GIOA ~func() E.Either[error, R]")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ", R any](f func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j)
}
fmt.Fprintf(fg, ") GRA) F {\n")
fmt.Fprintf(fg, " return func(c context.Context")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", t%d T%d", j, j)
}
fmt.Fprintf(fg, ") (R, error) {\n")
fmt.Fprintf(fg, " return E.UnwrapError(f(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d", j)
}
fmt.Fprintf(fg, ")(c)())\n")
fmt.Fprintf(fg, " }\n")
fmt.Fprintf(fg, "}\n")
}
func generateContextReaderIOEitherHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// construct subdirectory
genFilename := filepath.Join("generic", filename)
err = os.MkdirAll("generic", os.ModePerm)
if err != nil {
return err
}
fg, err := os.Create(filepath.Clean(genFilename))
if err != nil {
return err
}
defer fg.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
writePackage(f, pkg)
fmt.Fprintf(f, `
import (
"context"
G "github.com/IBM/fp-go/v2/context/%s/generic"
T "github.com/IBM/fp-go/v2/tuple"
)
`, pkg)
writePackage(fg, "generic")
fmt.Fprintf(fg, `
import (
"context"
E "github.com/IBM/fp-go/v2/either"
RE "github.com/IBM/fp-go/v2/readerioeither/generic"
A "github.com/IBM/fp-go/v2/internal/apply"
T "github.com/IBM/fp-go/v2/tuple"
)
`)
generateContextReaderIOEitherEitherize(f, fg, 0)
generateContextReaderIOEitherUneitherize(f, fg, 0)
for i := 1; i <= count; i++ {
// eitherize
generateContextReaderIOEitherEitherize(f, fg, i)
generateContextReaderIOEitherUneitherize(f, fg, i)
// sequenceT
generateContextReaderIOEitherSequenceT("")(f, fg, i)
generateContextReaderIOEitherSequenceT("Seq")(f, fg, i)
generateContextReaderIOEitherSequenceT("Par")(f, fg, i)
// sequenceTuple
generateContextReaderIOEitherSequenceTuple("")(f, fg, i)
generateContextReaderIOEitherSequenceTuple("Seq")(f, fg, i)
generateContextReaderIOEitherSequenceTuple("Par")(f, fg, i)
// traverseTuple
generateContextReaderIOEitherTraverseTuple("")(f, fg, i)
generateContextReaderIOEitherTraverseTuple("Seq")(f, fg, i)
generateContextReaderIOEitherTraverseTuple("Par")(f, fg, i)
}
return nil
}
func ContextReaderIOEitherCommand() *C.Command {
return &C.Command{
Name: "contextreaderioeither",
Usage: "generate code for ContextReaderIOEither",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateContextReaderIOEitherHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

231
v2/cli/di.go Normal file
View File

@@ -0,0 +1,231 @@
// 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 cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
C "github.com/urfave/cli/v2"
)
func generateMakeProvider(f *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// MakeProvider%d creates a [DIE.Provider] for an [InjectionToken] from a function with %d dependencies\n", i, i)
fmt.Fprintf(f, "func MakeProvider%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, " any, R any](\n")
fmt.Fprintf(f, " token InjectionToken[R],\n")
for j := 0; j < i; j++ {
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
}
fmt.Fprintf(f, " f func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") IOE.IOEither[error, R],\n")
fmt.Fprintf(f, ") DIE.Provider {\n")
fmt.Fprint(f, " return DIE.MakeProvider(\n")
fmt.Fprint(f, " token,\n")
fmt.Fprintf(f, " MakeProviderFactory%d(\n", i)
for j := 0; j < i; j++ {
fmt.Fprintf(f, " d%d,\n", j+1)
}
fmt.Fprint(f, " f,\n")
fmt.Fprint(f, " ))\n")
fmt.Fprintf(f, "}\n")
}
func generateMakeTokenWithDefault(f *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// MakeTokenWithDefault%d creates an [InjectionToken] with a default implementation with %d dependencies\n", i, i)
fmt.Fprintf(f, "func MakeTokenWithDefault%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, " any, R any](\n")
fmt.Fprintf(f, " name string,\n")
for j := 0; j < i; j++ {
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
}
fmt.Fprintf(f, " f func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") IOE.IOEither[error, R],\n")
fmt.Fprintf(f, ") InjectionToken[R] {\n")
fmt.Fprintf(f, " return MakeTokenWithDefault[R](name, MakeProviderFactory%d(\n", i)
for j := 0; j < i; j++ {
fmt.Fprintf(f, " d%d,\n", j+1)
}
fmt.Fprint(f, " f,\n")
fmt.Fprint(f, " ))\n")
fmt.Fprintf(f, "}\n")
}
func generateMakeProviderFactory(f *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// MakeProviderFactory%d creates a [DIE.ProviderFactory] from a function with %d arguments and %d dependencies\n", i, i, i)
fmt.Fprintf(f, "func MakeProviderFactory%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, " any, R any](\n")
for j := 0; j < i; j++ {
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
}
fmt.Fprintf(f, " f func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") IOE.IOEither[error, R],\n")
fmt.Fprintf(f, ") DIE.ProviderFactory {\n")
fmt.Fprint(f, " return DIE.MakeProviderFactory(\n")
fmt.Fprint(f, " A.From[DIE.Dependency](\n")
for j := 0; j < i; j++ {
fmt.Fprintf(f, " d%d,\n", j+1)
}
fmt.Fprint(f, " ),\n")
fmt.Fprintf(f, " eraseProviderFactory%d(\n", i)
for j := 0; j < i; j++ {
fmt.Fprintf(f, " d%d,\n", j+1)
}
fmt.Fprint(f, " f,\n")
fmt.Fprint(f, " ),\n")
fmt.Fprint(f, " )\n")
fmt.Fprintf(f, "}\n")
}
func generateEraseProviderFactory(f *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// eraseProviderFactory%d creates a function that takes a variadic number of untyped arguments and from a function of %d strongly typed arguments and %d dependencies\n", i, i, i)
fmt.Fprintf(f, "func eraseProviderFactory%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, " any, R any](\n")
for j := 0; j < i; j++ {
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
}
fmt.Fprintf(f, " f func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {\n")
fmt.Fprintf(f, " ft := eraseTuple(T.Tupled%d(f))\n", i)
for j := 0; j < i; j++ {
fmt.Fprintf(f, " t%d := lookupAt[T%d](%d, d%d)\n", j+1, j+1, j, j+1)
}
fmt.Fprint(f, " return func(params ...any) IOE.IOEither[error, any] {\n")
fmt.Fprintf(f, " return ft(E.SequenceT%d(\n", i)
for j := 0; j < i; j++ {
fmt.Fprintf(f, " t%d(params),\n", j+1)
}
fmt.Fprint(f, " ))\n")
fmt.Fprint(f, " }\n")
fmt.Fprintf(f, "}\n")
}
func generateDIHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)
fmt.Fprint(f, `
import (
E "github.com/IBM/fp-go/v2/either"
IOE "github.com/IBM/fp-go/v2/ioeither"
T "github.com/IBM/fp-go/v2/tuple"
A "github.com/IBM/fp-go/v2/array"
DIE "github.com/IBM/fp-go/v2/di/erasure"
)
`)
for i := 1; i <= count; i++ {
generateEraseProviderFactory(f, i)
generateMakeProviderFactory(f, i)
generateMakeTokenWithDefault(f, i)
generateMakeProvider(f, i)
}
return nil
}
func DICommand() *C.Command {
return &C.Command{
Name: "di",
Usage: "generate code for the dependency injection package",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateDIHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

200
v2/cli/either.go Normal file
View File

@@ -0,0 +1,200 @@
// 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 cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
C "github.com/urfave/cli/v2"
)
func eitherHKT(typeE string) func(typeA string) string {
return func(typeA string) string {
return fmt.Sprintf("Either[%s, %s]", typeE, typeA)
}
}
func generateEitherTraverseTuple(f *os.File, i int) {
generateTraverseTuple1(eitherHKT("E"), "E")(f, i)
}
func generateEitherSequenceTuple(f *os.File, i int) {
generateSequenceTuple1(eitherHKT("E"), "E")(f, i)
}
func generateEitherSequenceT(f *os.File, i int) {
generateSequenceT1(eitherHKT("E"), "E")(f, i)
}
func generateUneitherize(f *os.File, i int) {
// Create the optionize version
fmt.Fprintf(f, "\n// Uneitherize%d converts a function with %d parameters returning an Either into a function with %d parameters returning a tuple\n// The inverse function is [Eitherize%d]\n", i, i, i, i)
fmt.Fprintf(f, "func Uneitherize%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") Either[error, R]")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") (R, error) {\n")
fmt.Fprintf(f, " return func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d T%d", j, j)
}
fmt.Fprintf(f, ") (R, error) {\n")
fmt.Fprintf(f, " return UnwrapError(f(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j)
}
fmt.Fprintln(f, "))")
fmt.Fprintln(f, " }")
fmt.Fprintln(f, "}")
}
func generateEitherize(f *os.File, i int) {
// Create the optionize version
fmt.Fprintf(f, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning an Either\n// The inverse function is [Uneitherize%d]\n", i, i, i, i)
fmt.Fprintf(f, "func Eitherize%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") (R, error)")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") Either[error, R] {\n")
fmt.Fprintf(f, " return func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d T%d", j, j)
}
fmt.Fprintf(f, ") Either[error, R] {\n")
fmt.Fprintf(f, " return TryCatchError(f(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j)
}
fmt.Fprintln(f, "))")
fmt.Fprintln(f, " }")
fmt.Fprintln(f, "}")
}
func generateEitherHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)
fmt.Fprintf(f, `
import (
A "github.com/IBM/fp-go/v2/internal/apply"
T "github.com/IBM/fp-go/v2/tuple"
)
`)
// zero level functions
// optionize
generateEitherize(f, 0)
// unoptionize
generateUneitherize(f, 0)
for i := 1; i <= count; i++ {
// optionize
generateEitherize(f, i)
// unoptionize
generateUneitherize(f, i)
// sequenceT
generateEitherSequenceT(f, i)
// sequenceTuple
generateEitherSequenceTuple(f, i)
// traverseTuple
generateEitherTraverseTuple(f, i)
}
return nil
}
func EitherCommand() *C.Command {
return &C.Command{
Name: "either",
Usage: "generate code for Either",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateEitherHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

31
v2/cli/header.go Normal file
View 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 cli
import (
"fmt"
"os"
"time"
)
func writePackage(f *os.File, pkg string) {
// print package
fmt.Fprintf(f, "package %s\n\n", pkg)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
}

103
v2/cli/identity.go Normal file
View 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 cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
C "github.com/urfave/cli/v2"
)
func identityHKT(typeA string) string {
return typeA
}
func generateIdentityTraverseTuple(f *os.File, i int) {
generateTraverseTuple1(identityHKT, "")(f, i)
}
func generateIdentitySequenceTuple(f *os.File, i int) {
generateSequenceTuple1(identityHKT, "")(f, i)
}
func generateIdentitySequenceT(f *os.File, i int) {
generateSequenceT1(identityHKT, "")(f, i)
}
func generateIdentityHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)
fmt.Fprintf(f, `
import (
A "github.com/IBM/fp-go/v2/internal/apply"
T "github.com/IBM/fp-go/v2/tuple"
)
`)
for i := 1; i <= count; i++ {
// sequenceT
generateIdentitySequenceT(f, i)
// sequenceTuple
generateIdentitySequenceTuple(f, i)
// traverseTuple
generateIdentityTraverseTuple(f, i)
}
return nil
}
func IdentityCommand() *C.Command {
return &C.Command{
Name: "identity",
Usage: "generate code for Identity",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateIdentityHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

136
v2/cli/io.go Normal file
View File

@@ -0,0 +1,136 @@
// 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 cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
A "github.com/IBM/fp-go/v2/array"
C "github.com/urfave/cli/v2"
)
func nonGenericIO(param string) string {
return fmt.Sprintf("IO[%s]", param)
}
func genericIO(param string) string {
return fmt.Sprintf("func() %s", param)
}
var extrasIO = A.Empty[string]()
func generateIOSequenceT(f, fg *os.File, i int) {
generateGenericSequenceT(nonGenericIO, genericIO, extrasIO)(f, fg, i)
}
func generateIOSequenceTuple(f, fg *os.File, i int) {
generateGenericSequenceTuple(nonGenericIO, genericIO, extrasIO)(f, fg, i)
}
func generateIOTraverseTuple(f, fg *os.File, i int) {
generateGenericTraverseTuple(nonGenericIO, genericIO, extrasIO)(f, fg, i)
}
func generateIOHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// construct subdirectory
genFilename := filepath.Join("generic", filename)
err = os.MkdirAll("generic", os.ModePerm)
if err != nil {
return err
}
fg, err := os.Create(filepath.Clean(genFilename))
if err != nil {
return err
}
defer fg.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)
fmt.Fprintf(f, `
import (
G "github.com/IBM/fp-go/v2/%s/generic"
T "github.com/IBM/fp-go/v2/tuple"
)
`, pkg)
// some header
fmt.Fprintln(fg, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(fg, "// This file was generated by robots at")
fmt.Fprintf(fg, "// %s\n", time.Now())
fmt.Fprintf(fg, "package generic\n\n")
fmt.Fprintf(fg, `
import (
T "github.com/IBM/fp-go/v2/tuple"
A "github.com/IBM/fp-go/v2/internal/apply"
)
`)
for i := 1; i <= count; i++ {
// sequenceT
generateIOSequenceT(f, fg, i)
// sequenceTuple
generateIOSequenceTuple(f, fg, i)
// traverseTuple
generateIOTraverseTuple(f, fg, i)
}
return nil
}
func IOCommand() *C.Command {
return &C.Command{
Name: "io",
Usage: "generate code for IO",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateIOHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

282
v2/cli/ioeither.go Normal file
View File

@@ -0,0 +1,282 @@
// 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 cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
A "github.com/IBM/fp-go/v2/array"
C "github.com/urfave/cli/v2"
)
// [GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GTAB ~func() ET.Either[E, T.Tuple2[A, B]], E, A, B any](a GA, b GB) GTAB {
func nonGenericIOEither(param string) string {
return fmt.Sprintf("IOEither[E, %s]", param)
}
func genericIOEither(param string) string {
return fmt.Sprintf("func() ET.Either[E, %s]", param)
}
var extrasIOEither = A.From("E")
func generateIOEitherSequenceT(f, fg *os.File, i int) {
generateGenericSequenceT(nonGenericIOEither, genericIOEither, extrasIOEither)(f, fg, i)
}
func generateIOEitherSequenceTuple(f, fg *os.File, i int) {
generateGenericSequenceTuple(nonGenericIOEither, genericIOEither, extrasIOEither)(f, fg, i)
}
func generateIOEitherTraverseTuple(f, fg *os.File, i int) {
generateGenericTraverseTuple(nonGenericIOEither, genericIOEither, extrasIOEither)(f, fg, i)
}
func generateIOEitherUneitherize(f, fg *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// Uneitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [IOEither[error, R]]\n", i, i+1, i)
fmt.Fprintf(f, "func Uneitherize%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") IOEither[error, R]")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j+1)
}
fmt.Fprintf(f, ", R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") (R, error) {\n")
fmt.Fprintf(f, " return G.Uneitherize%d[IOEither[error, R]](f)\n", i)
fmt.Fprintln(f, "}")
// generic version
fmt.Fprintf(fg, "\n// Uneitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [GIOA]\n", i, i, i)
fmt.Fprintf(fg, "func Uneitherize%d[GIOA ~func() ET.Either[error, R], GTA ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j+1)
}
fmt.Fprintf(fg, ") GIOA")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j+1)
}
fmt.Fprintf(fg, ", R any](f GTA) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j+1)
}
fmt.Fprintf(fg, ") (R, error) {\n")
fmt.Fprintf(fg, " return func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d T%d", j+1, j+1)
}
fmt.Fprintf(fg, ") (R, error) {\n")
fmt.Fprintf(fg, " return ET.Unwrap(f(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d", j+1)
}
fmt.Fprintf(fg, ")())\n")
fmt.Fprintf(fg, " }\n")
fmt.Fprintf(fg, "}\n")
}
func generateIOEitherEitherize(f, fg *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [IOEither[error, R]]\n", i, i+1, i)
fmt.Fprintf(f, "func Eitherize%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") (R, error)")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j+1)
}
fmt.Fprintf(f, ", R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") IOEither[error, R] {\n")
fmt.Fprintf(f, " return G.Eitherize%d[IOEither[error, R]](f)\n", i)
fmt.Fprintln(f, "}")
// generic version
fmt.Fprintf(fg, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [GIOA]\n", i, i, i)
fmt.Fprintf(fg, "func Eitherize%d[GIOA ~func() ET.Either[error, R], F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j+1)
}
fmt.Fprintf(fg, ") (R, error)")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j+1)
}
fmt.Fprintf(fg, ", R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j+1)
}
fmt.Fprintf(fg, ") GIOA {\n")
fmt.Fprintf(fg, " e := ET.Eitherize%d(f)\n", i)
fmt.Fprintf(fg, " return func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d T%d", j+1, j+1)
}
fmt.Fprintf(fg, ") GIOA {\n")
fmt.Fprintf(fg, " return func() ET.Either[error, R] {\n")
fmt.Fprintf(fg, " return e(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d", j+1)
}
fmt.Fprintf(fg, ")\n")
fmt.Fprintf(fg, " }}\n")
fmt.Fprintf(fg, "}\n")
}
func generateIOEitherHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// construct subdirectory
genFilename := filepath.Join("generic", filename)
err = os.MkdirAll("generic", os.ModePerm)
if err != nil {
return err
}
fg, err := os.Create(filepath.Clean(genFilename))
if err != nil {
return err
}
defer fg.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)
fmt.Fprintf(f, `
import (
G "github.com/IBM/fp-go/v2/%s/generic"
T "github.com/IBM/fp-go/v2/tuple"
)
`, pkg)
// some header
fmt.Fprintln(fg, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(fg, "// This file was generated by robots at")
fmt.Fprintf(fg, "// %s\n", time.Now())
fmt.Fprintf(fg, "package generic\n\n")
fmt.Fprintf(fg, `
import (
ET "github.com/IBM/fp-go/v2/either"
T "github.com/IBM/fp-go/v2/tuple"
A "github.com/IBM/fp-go/v2/internal/apply"
)
`)
// eitherize
generateIOEitherEitherize(f, fg, 0)
// uneitherize
generateIOEitherUneitherize(f, fg, 0)
for i := 1; i <= count; i++ {
// eitherize
generateIOEitherEitherize(f, fg, i)
// uneitherize
generateIOEitherUneitherize(f, fg, i)
// sequenceT
generateIOEitherSequenceT(f, fg, i)
// sequenceTuple
generateIOEitherSequenceTuple(f, fg, i)
// traverseTuple
generateIOEitherTraverseTuple(f, fg, i)
}
return nil
}
func IOEitherCommand() *C.Command {
return &C.Command{
Name: "ioeither",
Usage: "generate code for IOEither",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateIOEitherHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

137
v2/cli/iooption.go Normal file
View File

@@ -0,0 +1,137 @@
// 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 cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
A "github.com/IBM/fp-go/v2/array"
C "github.com/urfave/cli/v2"
)
func nonGenericIOOption(param string) string {
return fmt.Sprintf("IOOption[%s]", param)
}
func genericIOOption(param string) string {
return fmt.Sprintf("func() O.Option[%s]", param)
}
var extrasIOOption = A.Empty[string]()
func generateIOOptionSequenceT(f, fg *os.File, i int) {
generateGenericSequenceT(nonGenericIOOption, genericIOOption, extrasIOOption)(f, fg, i)
}
func generateIOOptionSequenceTuple(f, fg *os.File, i int) {
generateGenericSequenceTuple(nonGenericIOOption, genericIOOption, extrasIOOption)(f, fg, i)
}
func generateIOOptionTraverseTuple(f, fg *os.File, i int) {
generateGenericTraverseTuple(nonGenericIOOption, genericIOOption, extrasIOOption)(f, fg, i)
}
func generateIOOptionHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// construct subdirectory
genFilename := filepath.Join("generic", filename)
err = os.MkdirAll("generic", os.ModePerm)
if err != nil {
return err
}
fg, err := os.Create(filepath.Clean(genFilename))
if err != nil {
return err
}
defer fg.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)
fmt.Fprintf(f, `
import (
G "github.com/IBM/fp-go/v2/%s/generic"
T "github.com/IBM/fp-go/v2/tuple"
)
`, pkg)
// some header
fmt.Fprintln(fg, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(fg, "// This file was generated by robots at")
fmt.Fprintf(fg, "// %s\n", time.Now())
fmt.Fprintf(fg, "package generic\n\n")
fmt.Fprintf(fg, `
import (
T "github.com/IBM/fp-go/v2/tuple"
O "github.com/IBM/fp-go/v2/option"
A "github.com/IBM/fp-go/v2/internal/apply"
)
`)
for i := 1; i <= count; i++ {
// sequenceT
generateIOOptionSequenceT(f, fg, i)
// sequenceTuple
generateIOOptionSequenceTuple(f, fg, i)
// traverseTuple
generateIOOptionTraverseTuple(f, fg, i)
}
return nil
}
func IOOptionCommand() *C.Command {
return &C.Command{
Name: "iooption",
Usage: "generate code for IOOption",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateIOOptionHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

359
v2/cli/monad.go Normal file
View File

@@ -0,0 +1,359 @@
// 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 cli
import (
"fmt"
"os"
"strings"
)
func tupleType(name string) func(i int) string {
return func(i int) string {
var buf strings.Builder
buf.WriteString(fmt.Sprintf("T.Tuple%d[", i))
for j := 0; j < i; j++ {
if j > 0 {
buf.WriteString(", ")
}
buf.WriteString(fmt.Sprintf("%s%d", name, j+1))
}
buf.WriteString("]")
return buf.String()
}
}
func monadGenerateSequenceTNonGeneric(
hkt func(string) string,
fmap func(string, string) string,
fap func(string, string) string,
) func(f *os.File, i int) {
return func(f *os.File, i int) {
tuple := tupleType("T")(i)
fmt.Fprintf(f, "SequenceT%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, "](")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d %s", j+1, hkt(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(f, ") %s {", hkt(tuple))
// the actual apply callback
fmt.Fprintf(f, " return apply.SequenceT%d(\n", i)
// map callback
curried := func(count int) string {
var buf strings.Builder
for j := count; j < i; j++ {
buf.WriteString(fmt.Sprintf("func(T%d)", j+1))
}
buf.WriteString(tuple)
return buf.String()
}
fmt.Fprintf(f, " %s,\n", fmap("T1", curried(1)))
for j := 1; j < i; j++ {
fmt.Fprintf(f, " %s,\n", fap(curried(j+1), fmt.Sprintf("T%d", j)))
}
for j := 0; j < i; j++ {
fmt.Fprintf(f, " T%d,\n", j+1)
}
fmt.Fprintf(f, " )\n")
fmt.Fprintf(f, "}\n")
}
}
func monadGenerateSequenceTGeneric(
hkt func(string) string,
fmap func(string, string) string,
fap func(string, string) string,
) func(f *os.File, i int) {
return func(f *os.File, i int) {
tuple := tupleType("T")(i)
fmt.Fprintf(f, "SequenceT%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, "](")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d %s", j+1, hkt(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(f, ") %s {", hkt(tuple))
// the actual apply callback
fmt.Fprintf(f, " return apply.SequenceT%d(\n", i)
// map callback
curried := func(count int) string {
var buf strings.Builder
for j := count; j < i; j++ {
buf.WriteString(fmt.Sprintf("func(T%d)", j+1))
}
buf.WriteString(tuple)
return buf.String()
}
fmt.Fprintf(f, " %s,\n", fmap("T1", curried(1)))
for j := 1; j < i; j++ {
fmt.Fprintf(f, " %s,\n", fap(curried(j+1), fmt.Sprintf("T%d", j)))
}
for j := 0; j < i; j++ {
fmt.Fprintf(f, " T%d,\n", j+1)
}
fmt.Fprintf(f, " )\n")
fmt.Fprintf(f, "}\n")
}
}
func generateTraverseTuple1(
hkt func(string) string,
infix string) func(f *os.File, i int) {
return func(f *os.File, i int) {
tuple := tupleType("T")(i)
fmt.Fprintf(f, "\n// TraverseTuple%d converts a [Tuple%d] of [A] via transformation functions transforming [A] to [%s] into a [%s].\n", i, i, hkt("A"), hkt(fmt.Sprintf("Tuple%d", i)))
fmt.Fprintf(f, "func TraverseTuple%d[", i)
// functions
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "F%d ~func(A%d) %s", j+1, j+1, hkt(fmt.Sprintf("T%d", j+1)))
}
if infix != "" {
fmt.Fprintf(f, ", %s", infix)
}
// types
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", A%d, T%d", j+1, j+1)
}
fmt.Fprintf(f, " any](")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "f%d F%d", j+1, j+1)
}
fmt.Fprintf(f, ") func (T.Tuple%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "A%d", j+1)
}
fmt.Fprintf(f, "]) %s {\n", hkt(tuple))
fmt.Fprintf(f, " return func(t T.Tuple%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "A%d", j+1)
}
fmt.Fprintf(f, "]) %s {\n", hkt(tuple))
fmt.Fprintf(f, " return A.TraverseTuple%d(\n", i)
// map
fmt.Fprintf(f, " Map[")
if infix != "" {
fmt.Fprintf(f, "%s, T1,", infix)
} else {
fmt.Fprintf(f, "T1,")
}
for j := 1; j < i; j++ {
fmt.Fprintf(f, " func(T%d)", j+1)
}
fmt.Fprintf(f, " %s],\n", tuple)
// applicatives
for j := 1; j < i; j++ {
fmt.Fprintf(f, " Ap[")
for k := j + 1; k < i; k++ {
if k > j+1 {
fmt.Fprintf(f, " ")
}
fmt.Fprintf(f, "func(T%d)", k+1)
}
if j < i-1 {
fmt.Fprintf(f, " ")
}
fmt.Fprintf(f, "%s", tuple)
if infix != "" {
fmt.Fprintf(f, ", %s", infix)
}
fmt.Fprintf(f, ", T%d],\n", j+1)
}
for j := 0; j < i; j++ {
fmt.Fprintf(f, " f%d,\n", j+1)
}
fmt.Fprintf(f, " t,\n")
fmt.Fprintf(f, " )\n")
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, "}\n")
}
}
func generateSequenceTuple1(
hkt func(string) string,
infix string) func(f *os.File, i int) {
return func(f *os.File, i int) {
tuple := tupleType("T")(i)
fmt.Fprintf(f, "\n// SequenceTuple%d converts a [Tuple%d] of [%s] into an [%s].\n", i, i, hkt("T"), hkt(fmt.Sprintf("Tuple%d", i)))
fmt.Fprintf(f, "func SequenceTuple%d[", i)
if infix != "" {
fmt.Fprintf(f, "%s", infix)
}
for j := 0; j < i; j++ {
if infix != "" || j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, " any](t T.Tuple%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "%s", hkt(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(f, "]) %s {\n", hkt(tuple))
fmt.Fprintf(f, " return A.SequenceTuple%d(\n", i)
// map
fmt.Fprintf(f, " Map[")
if infix != "" {
fmt.Fprintf(f, "%s, T1,", infix)
} else {
fmt.Fprintf(f, "T1,")
}
for j := 1; j < i; j++ {
fmt.Fprintf(f, " func(T%d)", j+1)
}
fmt.Fprintf(f, " %s],\n", tuple)
// applicatives
for j := 1; j < i; j++ {
fmt.Fprintf(f, " Ap[")
for k := j + 1; k < i; k++ {
if k > j+1 {
fmt.Fprintf(f, " ")
}
fmt.Fprintf(f, "func(T%d)", k+1)
}
if j < i-1 {
fmt.Fprintf(f, " ")
}
fmt.Fprintf(f, "%s", tuple)
if infix != "" {
fmt.Fprintf(f, ", %s", infix)
}
fmt.Fprintf(f, ", T%d],\n", j+1)
}
fmt.Fprintf(f, " t,\n")
fmt.Fprintf(f, " )\n")
fmt.Fprintf(f, "}\n")
}
}
func generateSequenceT1(
hkt func(string) string,
infix string) func(f *os.File, i int) {
return func(f *os.File, i int) {
tuple := tupleType("T")(i)
fmt.Fprintf(f, "\n// SequenceT%d converts %d parameters of [%s] into a [%s].\n", i, i, hkt("T"), hkt(fmt.Sprintf("Tuple%d", i)))
fmt.Fprintf(f, "func SequenceT%d[", i)
if infix != "" {
fmt.Fprintf(f, "%s", infix)
}
for j := 0; j < i; j++ {
if infix != "" || j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, " any](")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d %s", j+1, hkt(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(f, ") %s {\n", hkt(tuple))
fmt.Fprintf(f, " return A.SequenceT%d(\n", i)
// map
fmt.Fprintf(f, " Map[")
if infix != "" {
fmt.Fprintf(f, "%s, T1,", infix)
} else {
fmt.Fprintf(f, "T1,")
}
for j := 1; j < i; j++ {
fmt.Fprintf(f, " func(T%d)", j+1)
}
fmt.Fprintf(f, " %s],\n", tuple)
// applicatives
for j := 1; j < i; j++ {
fmt.Fprintf(f, " Ap[")
for k := j + 1; k < i; k++ {
if k > j+1 {
fmt.Fprintf(f, " ")
}
fmt.Fprintf(f, "func(T%d)", k+1)
}
if j < i-1 {
fmt.Fprintf(f, " ")
}
fmt.Fprintf(f, "%s", tuple)
if infix != "" {
fmt.Fprintf(f, ", %s", infix)
}
fmt.Fprintf(f, ", T%d],\n", j+1)
}
for j := 0; j < i; j++ {
fmt.Fprintf(f, " t%d,\n", j+1)
}
fmt.Fprintf(f, " )\n")
fmt.Fprintf(f, "}\n")
}
}

284
v2/cli/monad2.go Normal file
View File

@@ -0,0 +1,284 @@
// 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 cli
import (
"fmt"
"os"
A "github.com/IBM/fp-go/v2/array"
F "github.com/IBM/fp-go/v2/function"
N "github.com/IBM/fp-go/v2/number"
S "github.com/IBM/fp-go/v2/string"
)
var (
concStrgs = A.Monoid[string]().Concat
intercalStrgs = A.Intercalate(S.Monoid)
concAllStrgs = A.ConcatAll(A.Monoid[string]())
)
func joinAll(middle string) func(all ...[]string) string {
ic := intercalStrgs(middle)
return func(all ...[]string) string {
return ic(concAllStrgs(all))
}
}
func generateGenericSequenceT(
nonGenericType func(string) string,
genericType func(string) string,
extra []string,
) func(f, fg *os.File, i int) {
return func(f, fg *os.File, i int) {
// tuple
tuple := tupleType("T")(i)
// all types T
typesT := A.MakeBy(i, F.Flow2(
N.Inc[int],
S.Format[int]("T%d"),
))
// non generic version
fmt.Fprintf(f, "\n// SequenceT%d converts %d [%s] into a [%s]\n", i, i, nonGenericType("T"), nonGenericType(tuple))
fmt.Fprintf(f, "func SequenceT%d[%s any](\n", i, joinAll(", ")(extra, typesT))
for j := 0; j < i; j++ {
fmt.Fprintf(f, " t%d %s,\n", j+1, nonGenericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(f, ") %s {\n", nonGenericType(tuple))
fmt.Fprintf(f, " return G.SequenceT%d[\n", i)
fmt.Fprintf(f, " %s,\n", nonGenericType(tuple))
for j := 0; j < i; j++ {
fmt.Fprintf(f, " %s,\n", nonGenericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(f, " ](")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j+1)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
// generic version
fmt.Fprintf(fg, "\n// SequenceT%d converts %d [%s] into a [%s]\n", i, i, genericType("T"), genericType(tuple))
fmt.Fprintf(fg, "func SequenceT%d[\n", i)
fmt.Fprintf(fg, " G_TUPLE%d ~%s,\n", i, genericType(tuple))
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " G_T%d ~%s, \n", j+1, genericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(fg, " %s any](\n", joinAll(", ")(extra, typesT))
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " t%d G_T%d,\n", j+1, j+1)
}
fmt.Fprintf(fg, ") G_TUPLE%d {\n", i)
fmt.Fprintf(fg, " return A.SequenceT%d(\n", i)
// map call
var cio string
cb := generateNestedCallbacks(1, i)
if i > 1 {
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Map[%s],\n", joinAll(", ")(A.From("G_T1", cio), extra, A.From("T1", cb)))
// the apply calls
for j := 1; j < i; j++ {
if j < i-1 {
cb := generateNestedCallbacks(j+1, i)
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Ap[%s, %s, G_T%d],\n", cio, genericType(generateNestedCallbacks(j, i)), j+1)
}
// function parameters
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " t%d,\n", j+1)
}
fmt.Fprintf(fg, " )\n")
fmt.Fprintf(fg, "}\n")
}
}
func generateGenericSequenceTuple(
nonGenericType func(string) string,
genericType func(string) string,
extra []string,
) func(f, fg *os.File, i int) {
return func(f, fg *os.File, i int) {
// tuple
tuple := tupleType("T")(i)
// all types T
typesT := A.MakeBy(i, F.Flow2(
N.Inc[int],
S.Format[int]("T%d"),
))
// non generic version
fmt.Fprintf(f, "\n// SequenceTuple%d converts a [T.Tuple%d[%s]] into a [%s]\n", i, i, nonGenericType("T"), nonGenericType(tuple))
fmt.Fprintf(f, "func SequenceTuple%d[%s any](t T.Tuple%d[", i, joinAll(", ")(extra, typesT), i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "%s", nonGenericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(f, "]) %s {\n", nonGenericType(tuple))
fmt.Fprintf(f, " return G.SequenceTuple%d[\n", i)
fmt.Fprintf(f, " %s,\n", nonGenericType(tuple))
for j := 0; j < i; j++ {
fmt.Fprintf(f, " %s,\n", nonGenericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(f, " ](t)\n")
fmt.Fprintf(f, "}\n")
// generic version
fmt.Fprintf(fg, "\n// SequenceTuple%d converts a [T.Tuple%d[%s]] into a [%s]\n", i, i, genericType("T"), genericType(tuple))
fmt.Fprintf(fg, "func SequenceTuple%d[\n", i)
fmt.Fprintf(fg, " G_TUPLE%d ~%s,\n", i, genericType(tuple))
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " G_T%d ~%s, \n", j+1, genericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(fg, " %s any](t T.Tuple%d[", joinAll(", ")(extra, typesT), i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "G_T%d", j+1)
}
fmt.Fprintf(fg, "]) G_TUPLE%d {\n", i)
fmt.Fprintf(fg, " return A.SequenceTuple%d(\n", i)
// map call
var cio string
cb := generateNestedCallbacks(1, i)
if i > 1 {
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Map[%s],\n", joinAll(", ")(A.From("G_T1", cio), extra, A.From("T1", cb)))
// the apply calls
for j := 1; j < i; j++ {
if j < i-1 {
cb := generateNestedCallbacks(j+1, i)
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Ap[%s, %s, G_T%d],\n", cio, genericType(generateNestedCallbacks(j, i)), j+1)
}
// function parameters
fmt.Fprintf(fg, " t)\n")
fmt.Fprintf(fg, "}\n")
}
}
func generateGenericTraverseTuple(
nonGenericType func(string) string,
genericType func(string) string,
extra []string,
) func(f, fg *os.File, i int) {
return func(f, fg *os.File, i int) {
// tuple
tupleT := tupleType("T")(i)
tupleA := tupleType("A")(i)
// all types T
typesT := A.MakeBy(i, F.Flow2(
N.Inc[int],
S.Format[int]("T%d"),
))
// all types A
typesA := A.MakeBy(i, F.Flow2(
N.Inc[int],
S.Format[int]("A%d"),
))
// all function types
typesF := A.MakeBy(i, F.Flow2(
N.Inc[int],
func(j int) string {
return fmt.Sprintf("F%d ~func(A%d) %s", j, j, nonGenericType(fmt.Sprintf("T%d", j)))
},
))
// non generic version
fmt.Fprintf(f, "\n// TraverseTuple%d converts a [T.Tuple%d[%s]] into a [%s]\n", i, i, nonGenericType("T"), nonGenericType(tupleT))
fmt.Fprintf(f, "func TraverseTuple%d[%s any](", i, joinAll(", ")(typesF, extra, typesA, typesT))
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "f%d F%d", j+1, j+1)
}
fmt.Fprintf(f, ") func(%s) %s {\n", tupleA, nonGenericType(tupleT))
fmt.Fprintf(f, " return G.TraverseTuple%d[%s](", i, nonGenericType(tupleT))
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "f%d", j+1)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
// generic version
fmt.Fprintf(fg, "\n// TraverseTuple%d converts a [T.Tuple%d[%s]] into a [%s]\n", i, i, genericType("T"), genericType(tupleT))
fmt.Fprintf(fg, "func TraverseTuple%d[\n", i)
fmt.Fprintf(fg, " G_TUPLE%d ~%s,\n", i, genericType(tupleT))
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " F%d ~func(A%d) G_T%d,\n", j+1, j+1, j+1)
}
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " G_T%d ~%s, \n", j+1, genericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(fg, " %s any](", joinAll(", ")(extra, typesA, typesT))
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "f%d F%d", j+1, j+1)
}
fmt.Fprintf(fg, ") func(%s) G_TUPLE%d {\n", tupleA, i)
fmt.Fprintf(fg, " return func(t %s) G_TUPLE%d {\n", tupleA, i)
fmt.Fprintf(fg, " return A.TraverseTuple%d(\n", i)
// map call
var cio string
cb := generateNestedCallbacks(1, i)
if i > 1 {
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Map[%s],\n", joinAll(", ")(A.From("G_T1", cio), extra, A.From("T1", cb)))
// the apply calls
for j := 1; j < i; j++ {
if j < i-1 {
cb := generateNestedCallbacks(j+1, i)
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Ap[%s, %s, G_T%d],\n", cio, genericType(generateNestedCallbacks(j, i)), j+1)
}
// function parameters
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " f%d,\n", j+1)
}
// tuple parameter
fmt.Fprintf(fg, " t)\n")
fmt.Fprintf(fg, " }\n")
fmt.Fprintf(fg, "}\n")
}
}

210
v2/cli/option.go Normal file
View File

@@ -0,0 +1,210 @@
// 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 cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
C "github.com/urfave/cli/v2"
)
func optionHKT(typeA string) string {
return fmt.Sprintf("Option[%s]", typeA)
}
func generateOptionTraverseTuple(f *os.File, i int) {
generateTraverseTuple1(optionHKT, "")(f, i)
}
func generateOptionSequenceTuple(f *os.File, i int) {
generateSequenceTuple1(optionHKT, "")(f, i)
}
func generateOptionSequenceT(f *os.File, i int) {
generateSequenceT1(optionHKT, "")(f, i)
}
func generateOptionize(f *os.File, i int) {
// Create the optionize version
fmt.Fprintf(f, "\n// Optionize%d converts a function with %d parameters returning a tuple of a return value R and a boolean into a function with %d parameters returning an Option[R]\n", i, i, i)
fmt.Fprintf(f, "func Optionize%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") (R, bool)")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") Option[R] {\n")
fmt.Fprintf(f, " return func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d T%d", j, j)
}
fmt.Fprintf(f, ") Option[R] {\n")
fmt.Fprintf(f, " return optionize(func() (R, bool) {\n")
fmt.Fprintf(f, " return f(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j)
}
fmt.Fprintln(f, ")")
fmt.Fprintln(f, " })")
fmt.Fprintln(f, " }")
fmt.Fprintln(f, "}")
}
func generateUnoptionize(f *os.File, i int) {
// Create the optionize version
fmt.Fprintf(f, "\n// Unoptionize%d converts a function with %d parameters returning a tuple of a return value R and a boolean into a function with %d parameters returning an Option[R]\n", i, i, i)
fmt.Fprintf(f, "func Unoptionize%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") Option[R]")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") (R, bool) {\n")
fmt.Fprintf(f, " return func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d T%d", j, j)
}
fmt.Fprintf(f, ") (R, bool) {\n")
fmt.Fprintf(f, " return Unwrap(f(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j)
}
fmt.Fprintln(f, "))")
fmt.Fprintln(f, " }")
fmt.Fprintln(f, "}")
}
func generateOptionHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)
fmt.Fprintf(f, `
import (
A "github.com/IBM/fp-go/v2/internal/apply"
T "github.com/IBM/fp-go/v2/tuple"
)
`)
// print out some helpers
fmt.Fprintf(f, `// optionize converts a nullary function to an option
func optionize[R any](f func() (R, bool)) Option[R] {
if r, ok := f(); ok {
return Some(r)
}
return None[R]()
}
`)
// zero level functions
// optionize
generateOptionize(f, 0)
// unoptionize
generateUnoptionize(f, 0)
for i := 1; i <= count; i++ {
// optionize
generateOptionize(f, i)
// unoptionize
generateUnoptionize(f, i)
// sequenceT
generateOptionSequenceT(f, i)
// sequenceTuple
generateOptionSequenceTuple(f, i)
// traverseTuple
generateOptionTraverseTuple(f, i)
}
return nil
}
func OptionCommand() *C.Command {
return &C.Command{
Name: "option",
Usage: "generate code for Option",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateOptionHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

433
v2/cli/pipe.go Normal file
View File

@@ -0,0 +1,433 @@
// 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 cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
C "github.com/urfave/cli/v2"
)
func generateUnsliced(f *os.File, i int) {
// Create the optionize version
fmt.Fprintf(f, "\n// Unsliced%d converts a function taking a slice parameter into a function with %d parameters\n", i, i)
fmt.Fprintf(f, "func Unsliced%d[F ~func([]T) R, T, R any](f F) func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T")
}
fmt.Fprintf(f, ") R {\n")
fmt.Fprintf(f, " return func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j+1)
}
if i > 0 {
fmt.Fprintf(f, " T")
}
fmt.Fprintf(f, ") R {\n")
fmt.Fprintf(f, " return f([]T{")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j+1)
}
fmt.Fprintln(f, "})")
fmt.Fprintln(f, " }")
fmt.Fprintln(f, "}")
}
func generateVariadic(f *os.File, i int) {
// Create the nullary version
fmt.Fprintf(f, "\n// Variadic%d converts a function taking %d parameters and a final slice into a function with %d parameters but a final variadic argument\n", i, i, i)
fmt.Fprintf(f, "func Variadic%d[", i)
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "V, R any](f func(")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "[]V) R) func(")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "...V) R {\n")
fmt.Fprintf(f, " return func(")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d T%d", j, j)
}
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "v ...V) R {\n")
fmt.Fprintf(f, " return f(")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j)
}
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "v)\n")
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, "}\n")
}
func generateUnvariadic(f *os.File, i int) {
// Create the nullary version
fmt.Fprintf(f, "\n// Unvariadic%d converts a function taking %d parameters and a final variadic argument into a function with %d parameters but a final slice argument\n", i, i, i)
fmt.Fprintf(f, "func Unvariadic%d[", i)
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "V, R any](f func(")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "...V) R) func(")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "[]V) R {\n")
fmt.Fprintf(f, " return func(")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d T%d", j, j)
}
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "v []V) R {\n")
fmt.Fprintf(f, " return f(")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j)
}
if i > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "v...)\n")
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, "}\n")
}
func generateNullary(f *os.File, i int) {
// Create the nullary version
fmt.Fprintf(f, "\n// Nullary%d creates a parameter less function from a parameter less function and %d functions. When executed the first parameter less function gets executed and then the result is piped through the remaining functions\n", i, i-1)
fmt.Fprintf(f, "func Nullary%d[F1 ~func() T1", i)
for j := 2; j <= i; j++ {
fmt.Fprintf(f, ", F%d ~func(T%d) T%d", j, j-1, j)
}
for j := 1; j <= i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, " any](f1 F1")
for j := 2; j <= i; j++ {
fmt.Fprintf(f, ", f%d F%d", j, j)
}
fmt.Fprintf(f, ") func() T%d {\n", i)
fmt.Fprintf(f, " return func() T%d {\n", i)
fmt.Fprintf(f, " return Pipe%d(f1()", i-1)
for j := 2; j <= i; j++ {
fmt.Fprintf(f, ", f%d", j)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintln(f, " }")
fmt.Fprintln(f, "}")
}
func generateFlow(f *os.File, i int) {
// Create the flow version
fmt.Fprintf(f, "\n// Flow%d creates a function that takes an initial value t0 and successively applies %d functions where the input of a function is the return value of the previous function\n// The final return value is the result of the last function application\n", i, i)
fmt.Fprintf(f, "func Flow%d[", i)
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "F%d ~func(T%d) T%d", j, j-1, j)
}
for j := 0; j <= i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, " any](")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "f%d F%d", j, j)
}
fmt.Fprintf(f, ") func(T0) T%d {\n", i)
fmt.Fprintf(f, " return func(t0 T0) T%d {\n", i)
fmt.Fprintf(f, " return Pipe%d(t0", i)
for j := 1; j <= i; j++ {
fmt.Fprintf(f, ", f%d", j)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintln(f, " }")
fmt.Fprintln(f, "}")
}
func generatePipe(f *os.File, i int) {
// Create the pipe version
fmt.Fprintf(f, "\n// Pipe%d takes an initial value t0 and successively applies %d functions where the input of a function is the return value of the previous function\n// The final return value is the result of the last function application\n", i, i)
fmt.Fprintf(f, "func Pipe%d[", i)
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "F%d ~func(T%d) T%d", j, j-1, j)
}
if i > 0 {
fmt.Fprintf(f, ", ")
}
for j := 0; j <= i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, " any](t0 T0")
for j := 1; j <= i; j++ {
fmt.Fprintf(f, ", f%d F%d", j, j)
}
fmt.Fprintf(f, ") T%d {\n", i)
fmt.Fprintf(f, " return ")
for j := i; j >= 1; j-- {
fmt.Fprintf(f, "f%d(", j)
}
fmt.Fprintf(f, "t0")
for j := 1; j <= i; j++ {
fmt.Fprintf(f, ")")
}
fmt.Fprintf(f, "\n")
fmt.Fprintln(f, "}")
}
func recurseCurry(f *os.File, indent string, total, count int) {
if count == 1 {
fmt.Fprintf(f, "%sreturn func(t%d T%d) T%d {\n", indent, total-1, total-1, total)
fmt.Fprintf(f, "%s return f(t0", indent)
for i := 1; i < total; i++ {
fmt.Fprintf(f, ", t%d", i)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "%s}\n", indent)
} else {
fmt.Fprintf(f, "%sreturn", indent)
for i := total - count + 1; i <= total; i++ {
fmt.Fprintf(f, " func(t%d T%d)", i-1, i-1)
}
fmt.Fprintf(f, " T%d {\n", total)
recurseCurry(f, fmt.Sprintf(" %s", indent), total, count-1)
fmt.Fprintf(f, "%s}\n", indent)
}
}
func generateCurry(f *os.File, i int) {
// Create the curry version
fmt.Fprintf(f, "\n// Curry%d takes a function with %d parameters and returns a cascade of functions each taking only one parameter.\n// The inverse function is [Uncurry%d]\n", i, i, i)
fmt.Fprintf(f, "func Curry%d[FCT ~func(T0", i)
for j := 1; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ") T%d", i)
// type arguments
for j := 0; j <= i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, " any](f FCT) func(T0)")
for j := 2; j <= i; j++ {
fmt.Fprintf(f, " func(T%d)", j-1)
}
fmt.Fprintf(f, " T%d {\n", i)
recurseCurry(f, " ", i, i)
fmt.Fprintf(f, "}\n")
}
func generateUncurry(f *os.File, i int) {
// Create the uncurry version
fmt.Fprintf(f, "\n// Uncurry%d takes a cascade of %d functions each taking only one parameter and returns a function with %d parameters .\n// The inverse function is [Curry%d]\n", i, i, i, i)
fmt.Fprintf(f, "func Uncurry%d[FCT ~func(T0)", i)
for j := 1; j < i; j++ {
fmt.Fprintf(f, " func(T%d)", j)
}
fmt.Fprintf(f, " T%d", i)
// the type parameters
for j := 0; j <= i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, " any](f FCT) func(")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j-1)
}
fmt.Fprintf(f, ") T%d {\n", i)
fmt.Fprintf(f, " return func(")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d T%d", j-1, j-1)
}
fmt.Fprintf(f, ") T%d {\n", i)
fmt.Fprintf(f, " return f")
for j := 1; j <= i; j++ {
fmt.Fprintf(f, "(t%d)", j-1)
}
fmt.Fprintln(f)
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, "}\n")
}
func generatePipeHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n", pkg)
// pipe
generatePipe(f, 0)
// variadic
generateVariadic(f, 0)
// unvariadic
generateUnvariadic(f, 0)
// unsliced
generateUnsliced(f, 0)
for i := 1; i <= count; i++ {
// pipe
generatePipe(f, i)
// flow
generateFlow(f, i)
// nullary
generateNullary(f, i)
// curry
generateCurry(f, i)
// uncurry
generateUncurry(f, i)
// variadic
generateVariadic(f, i)
// unvariadic
generateUnvariadic(f, i)
// unsliced
generateUnsliced(f, i)
}
return nil
}
func PipeCommand() *C.Command {
return &C.Command{
Name: "pipe",
Usage: "generate code for pipe, flow, curry, etc",
Description: "Code generation for pipe, flow, curry, etc",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generatePipeHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

164
v2/cli/reader.go Normal file
View File

@@ -0,0 +1,164 @@
// 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 cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
C "github.com/urfave/cli/v2"
)
func generateReaderFrom(f, fg *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// From%d converts a function with %d parameters returning a [R] into a function with %d parameters returning a [Reader[C, R]]\n// The first parameter is considered to be the context [C] of the reader\n", i, i+1, i)
fmt.Fprintf(f, "func From%d[F ~func(C", i)
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ") R")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", C, R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") Reader[C, R] {\n")
fmt.Fprintf(f, " return G.From%d[Reader[C, R]](f)\n", i)
fmt.Fprintln(f, "}")
// generic version
fmt.Fprintf(fg, "\n// From%d converts a function with %d parameters returning a [R] into a function with %d parameters returning a [GRA]\n// The first parameter is considered to be the context [C].\n", i, i+1, i)
fmt.Fprintf(fg, "func From%d[GRA ~func(C) R, F ~func(C", i)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ") R")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ", C, R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j)
}
fmt.Fprintf(fg, ") GRA {\n")
fmt.Fprintf(fg, " return func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d T%d", j, j)
}
fmt.Fprintf(fg, ") GRA {\n")
fmt.Fprintf(fg, " return MakeReader[GRA](func(r C) R {\n")
fmt.Fprintf(fg, " return f(r")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", t%d", j)
}
fmt.Fprintf(fg, ")\n")
fmt.Fprintf(fg, " })\n")
fmt.Fprintf(fg, " }\n")
fmt.Fprintf(fg, "}\n")
}
func generateReaderHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// construct subdirectory
genFilename := filepath.Join("generic", filename)
err = os.MkdirAll("generic", os.ModePerm)
if err != nil {
return err
}
fg, err := os.Create(filepath.Clean(genFilename))
if err != nil {
return err
}
defer fg.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)
fmt.Fprintf(f, `
import (
G "github.com/IBM/fp-go/v2/%s/generic"
)
`, pkg)
// some header
fmt.Fprintln(fg, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(fg, "// This file was generated by robots at")
fmt.Fprintf(fg, "// %s\n", time.Now())
fmt.Fprintf(fg, "package generic\n\n")
// from
generateReaderFrom(f, fg, 0)
for i := 1; i <= count; i++ {
// from
generateReaderFrom(f, fg, i)
}
return nil
}
func ReaderCommand() *C.Command {
return &C.Command{
Name: "reader",
Usage: "generate code for Reader",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateReaderHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

294
v2/cli/readerioeither.go Normal file
View File

@@ -0,0 +1,294 @@
// 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 cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
C "github.com/urfave/cli/v2"
)
func generateReaderIOEitherFrom(f, fg *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// From%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [ReaderIOEither[R]]\n// The first parameter is considered to be the context [C].\n", i, i+1, i)
fmt.Fprintf(f, "func From%d[F ~func(C", i)
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ") func() (R, error)")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", C, R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") ReaderIOEither[C, error, R] {\n")
fmt.Fprintf(f, " return G.From%d[ReaderIOEither[C, error, R]](f)\n", i)
fmt.Fprintln(f, "}")
// generic version
fmt.Fprintf(fg, "\n// From%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [GRA]\n// The first parameter is considerd to be the context [C].\n", i, i+1, i)
fmt.Fprintf(fg, "func From%d[GRA ~func(C) GIOA, F ~func(C", i)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ") func() (R, error), GIOA ~func() E.Either[error, R]")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ", C, R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j)
}
fmt.Fprintf(fg, ") GRA {\n")
fmt.Fprintf(fg, " return RD.From%d[GRA](func(r C", i)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", t%d T%d", j, j)
}
fmt.Fprintf(fg, ") GIOA {\n")
fmt.Fprintf(fg, " return E.Eitherize0(f(r")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", t%d", j)
}
fmt.Fprintf(fg, "))\n")
fmt.Fprintf(fg, " })\n")
fmt.Fprintf(fg, "}\n")
}
func generateReaderIOEitherEitherize(f, fg *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [ReaderIOEither[C, error, R]]\n// The first parameter is considered to be the context [C].\n", i, i+1, i)
fmt.Fprintf(f, "func Eitherize%d[F ~func(C", i)
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ") (R, error)")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", C, R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") ReaderIOEither[C, error, R] {\n")
fmt.Fprintf(f, " return G.Eitherize%d[ReaderIOEither[C, error, R]](f)\n", i)
fmt.Fprintln(f, "}")
// generic version
fmt.Fprintf(fg, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [GRA]\n// The first parameter is considered to be the context [C].\n", i, i, i)
fmt.Fprintf(fg, "func Eitherize%d[GRA ~func(C) GIOA, F ~func(C", i)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ") (R, error), GIOA ~func() E.Either[error, R]")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ", C, R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j)
}
fmt.Fprintf(fg, ") GRA {\n")
fmt.Fprintf(fg, " return From%d[GRA](func(r C", i)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", t%d T%d", j, j)
}
fmt.Fprintf(fg, ") func() (R, error) {\n")
fmt.Fprintf(fg, " return func() (R, error) {\n")
fmt.Fprintf(fg, " return f(r")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", t%d", j)
}
fmt.Fprintf(fg, ")\n")
fmt.Fprintf(fg, " }})\n")
fmt.Fprintf(fg, "}\n")
}
func generateReaderIOEitherUneitherize(f, fg *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// Uneitherize%d converts a function with %d parameters returning a [ReaderIOEither[C, error, R]] into a function with %d parameters returning a tuple.\n// The first parameter is considered to be the context [C].\n", i, i+1, i)
fmt.Fprintf(f, "func Uneitherize%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") ReaderIOEither[C, error, R]")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", C, R any](f F) func(C")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ") (R, error) {\n")
fmt.Fprintf(f, " return G.Uneitherize%d[ReaderIOEither[C, error, R]", i)
fmt.Fprintf(f, ", func(C")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ")(R, error)](f)\n")
fmt.Fprintln(f, "}")
// generic version
fmt.Fprintf(fg, "\n// Uneitherize%d converts a function with %d parameters returning a [GRA] into a function with %d parameters returning a tuple.\n// The first parameter is considered to be the context [C].\n", i, i, i)
fmt.Fprintf(fg, "func Uneitherize%d[GRA ~func(C) GIOA, F ~func(C", i)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ") (R, error), GIOA ~func() E.Either[error, R]")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ", C, R any](f func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j)
}
fmt.Fprintf(fg, ") GRA) F {\n")
fmt.Fprintf(fg, " return func(c C")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", t%d T%d", j, j)
}
fmt.Fprintf(fg, ") (R, error) {\n")
fmt.Fprintf(fg, " return E.UnwrapError(f(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d", j)
}
fmt.Fprintf(fg, ")(c)())\n")
fmt.Fprintf(fg, " }\n")
fmt.Fprintf(fg, "}\n")
}
func generateReaderIOEitherHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// construct subdirectory
genFilename := filepath.Join("generic", filename)
err = os.MkdirAll("generic", os.ModePerm)
if err != nil {
return err
}
fg, err := os.Create(filepath.Clean(genFilename))
if err != nil {
return err
}
defer fg.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)
fmt.Fprintf(f, `
import (
G "github.com/IBM/fp-go/v2/%s/generic"
)
`, pkg)
// some header
fmt.Fprintln(fg, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(fg, "// This file was generated by robots at")
fmt.Fprintf(fg, "// %s\n", time.Now())
fmt.Fprintf(fg, "package generic\n\n")
fmt.Fprintf(fg, `
import (
E "github.com/IBM/fp-go/v2/either"
RD "github.com/IBM/fp-go/v2/reader/generic"
)
`)
// from
generateReaderIOEitherFrom(f, fg, 0)
// eitherize
generateReaderIOEitherEitherize(f, fg, 0)
// uneitherize
generateReaderIOEitherUneitherize(f, fg, 0)
for i := 1; i <= count; i++ {
// from
generateReaderIOEitherFrom(f, fg, i)
// eitherize
generateReaderIOEitherEitherize(f, fg, i)
// uneitherize
generateReaderIOEitherUneitherize(f, fg, i)
}
return nil
}
func ReaderIOEitherCommand() *C.Command {
return &C.Command{
Name: "readerioeither",
Usage: "generate code for ReaderIOEither",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateReaderIOEitherHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

View File

@@ -0,0 +1,15 @@
package templates
import (
"text/template"
E "github.com/IBM/fp-go/v2/either"
)
var (
templateFunctions = template.FuncMap{}
)
func Parse(name, tmpl string) E.Either[error, *template.Template] {
return E.TryCatchError(template.New(name).Funcs(templateFunctions).Parse(tmpl))
}

625
v2/cli/tuple.go Normal file
View File

@@ -0,0 +1,625 @@
// 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 cli
import (
"fmt"
"log"
"os"
"path/filepath"
"strings"
"time"
C "github.com/urfave/cli/v2"
)
func writeTupleType(f *os.File, symbol string, i int) {
fmt.Fprintf(f, "Tuple%d[", i)
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "%s%d", symbol, j)
}
fmt.Fprintf(f, "]")
}
func makeTupleType(name string) func(i int) string {
return func(i int) string {
var buf strings.Builder
buf.WriteString(fmt.Sprintf("Tuple%d[", i))
for j := 0; j < i; j++ {
if j > 0 {
buf.WriteString(", ")
}
buf.WriteString(fmt.Sprintf("%s%d", name, j+1))
}
buf.WriteString("]")
return buf.String()
}
}
func generatePush(f *os.File, i int) {
tuple1 := makeTupleType("T")(i)
tuple2 := makeTupleType("T")(i + 1)
// Create the replicate version
fmt.Fprintf(f, "\n// Push%d creates a [Tuple%d] from a [Tuple%d] by appending a constant value\n", i, i+1, i)
fmt.Fprintf(f, "func Push%d[", i)
// function prototypes
for j := 0; j <= i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, " any](value T%d) func(%s) %s {\n", i+1, tuple1, tuple2)
fmt.Fprintf(f, " return func(t %s) %s {\n", tuple1, tuple2)
fmt.Fprintf(f, " return MakeTuple%d(", i+1)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t.F%d", j+1)
}
fmt.Fprintf(f, ", value)\n")
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, "}\n")
}
func generateReplicate(f *os.File, i int) {
// Create the replicate version
fmt.Fprintf(f, "\n// Replicate%d creates a [Tuple%d] with all fields set to the input value `t`\n", i, i)
fmt.Fprintf(f, "func Replicate%d[T any](t T) Tuple%d[", i, i)
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T")
}
fmt.Fprintf(f, "] {\n")
// execute the mapping
fmt.Fprintf(f, " return MakeTuple%d(", i)
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t")
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
}
func generateMap(f *os.File, i int) {
// Create the optionize version
fmt.Fprintf(f, "\n// Map%d maps each value of a [Tuple%d] via a mapping function\n", i, i)
fmt.Fprintf(f, "func Map%d[", i)
// function prototypes
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "F%d ~func(T%d) R%d", j, j, j)
}
for j := 1; j <= i; j++ {
fmt.Fprintf(f, ", T%d, R%d", j, j)
}
fmt.Fprintf(f, " any](")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "f%d F%d", j, j)
}
fmt.Fprintf(f, ") func(")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") ")
writeTupleType(f, "R", i)
fmt.Fprintf(f, " {\n")
fmt.Fprintf(f, " return func(t ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") ")
writeTupleType(f, "R", i)
fmt.Fprintf(f, " {\n")
// execute the mapping
fmt.Fprintf(f, " return MakeTuple%d(\n", i)
for j := 1; j <= i; j++ {
fmt.Fprintf(f, " f%d(t.F%d),\n", j, j)
}
fmt.Fprintf(f, " )\n")
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, "}\n")
}
func generateMonoid(f *os.File, i int) {
// Create the optionize version
fmt.Fprintf(f, "\n// Monoid%d creates a [Monoid] for a [Tuple%d] based on %d monoids for the contained types\n", i, i, i)
fmt.Fprintf(f, "func Monoid%d[", i)
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, " any](")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "m%d M.Monoid[T%d]", j, j)
}
fmt.Fprintf(f, ") M.Monoid[")
writeTupleType(f, "T", i)
fmt.Fprintf(f, "] {\n")
fmt.Fprintf(f, " return M.MakeMonoid(func(l, r ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, "{\n")
fmt.Fprintf(f, " return MakeTuple%d(", i)
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "m%d.Concat(l.F%d, r.F%d)", j, j, j)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, " }, MakeTuple%d(", i)
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "m%d.Empty()", j)
}
fmt.Fprintf(f, "))\n")
fmt.Fprintf(f, "}\n")
}
func generateOrd(f *os.File, i int) {
// Create the optionize version
fmt.Fprintf(f, "\n// Ord%d creates n [Ord] for a [Tuple%d] based on %d [Ord]s for the contained types\n", i, i, i)
fmt.Fprintf(f, "func Ord%d[", i)
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, " any](")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "o%d O.Ord[T%d]", j, j)
}
fmt.Fprintf(f, ") O.Ord[")
writeTupleType(f, "T", i)
fmt.Fprintf(f, "] {\n")
fmt.Fprintf(f, " return O.MakeOrd(func(l, r ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") int {\n")
for j := 1; j <= i; j++ {
fmt.Fprintf(f, " if c:= o%d.Compare(l.F%d, r.F%d); c != 0 {return c}\n", j, j, j)
}
fmt.Fprintf(f, " return 0\n")
fmt.Fprintf(f, " }, func(l, r ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") bool {\n")
fmt.Fprintf(f, " return ")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, " && ")
}
fmt.Fprintf(f, "o%d.Equals(l.F%d, r.F%d)", j, j, j)
}
fmt.Fprintf(f, "\n")
fmt.Fprintf(f, " })\n")
fmt.Fprintf(f, "}\n")
}
func generateTupleType(f *os.File, i int) {
// Create the optionize version
fmt.Fprintf(f, "\n// Tuple%d is a struct that carries %d independently typed values\n", i, i)
fmt.Fprintf(f, "type Tuple%d[", i)
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, " any] struct {\n")
for j := 1; j <= i; j++ {
fmt.Fprintf(f, " F%d T%d\n", j, j)
}
fmt.Fprintf(f, "}\n")
}
func generateMakeTupleType(f *os.File, i int) {
// Create the optionize version
fmt.Fprintf(f, "\n// MakeTuple%d is a function that converts its %d parameters into a [Tuple%d]\n", i, i, i)
fmt.Fprintf(f, "func MakeTuple%d[", i)
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, " any](")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d T%d", j, j)
}
fmt.Fprintf(f, ") ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, " {\n")
fmt.Fprintf(f, " return Tuple%d[", i)
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, "]{")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j)
}
fmt.Fprintf(f, "}\n")
fmt.Fprintf(f, "}\n")
}
func generateUntupled(f *os.File, i int) {
// Create the optionize version
fmt.Fprintf(f, "\n// Untupled%d converts a function with a [Tuple%d] parameter into a function with %d parameters\n// The inverse function is [Tupled%d]\n", i, i, i, i)
fmt.Fprintf(f, "func Untupled%d[F ~func(Tuple%d[", i, i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, "]) R")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j+1)
}
fmt.Fprintf(f, ", R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") R {\n")
fmt.Fprintf(f, " return func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d T%d", j+1, j+1)
}
fmt.Fprintf(f, ") R {\n")
fmt.Fprintf(f, " return f(MakeTuple%d(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j+1)
}
fmt.Fprintln(f, "))")
fmt.Fprintln(f, " }")
fmt.Fprintln(f, "}")
}
func generateTupled(f *os.File, i int) {
// Create the optionize version
fmt.Fprintf(f, "\n// Tupled%d converts a function with %d parameters into a function taking a Tuple%d\n// The inverse function is [Untupled%d]\n", i, i, i, i)
fmt.Fprintf(f, "func Tupled%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") R")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j+1)
}
fmt.Fprintf(f, ", R any](f F) func(Tuple%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, "]) R {\n")
fmt.Fprintf(f, " return func(t Tuple%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, "]) R {\n")
fmt.Fprintf(f, " return f(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t.F%d", j+1)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, " }\n")
fmt.Fprintln(f, "}")
}
func generateTupleHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)
fmt.Fprintf(f, `
import (
M "github.com/IBM/fp-go/v2/monoid"
O "github.com/IBM/fp-go/v2/ord"
)
`)
for i := 1; i <= count; i++ {
// tuple type
generateTupleType(f, i)
}
for i := 1; i <= count; i++ {
// tuple generator
generateMakeTupleType(f, i)
// tupled wrapper
generateTupled(f, i)
// untupled wrapper
generateUntupled(f, i)
// monoid
generateMonoid(f, i)
// generate order
generateOrd(f, i)
// generate map
generateMap(f, i)
// generate replicate
generateReplicate(f, i)
// generate tuple functions such as string and fmt
generateTupleString(f, i)
// generate json support
generateTupleMarshal(f, i)
// generate json support
generateTupleUnmarshal(f, i)
// generate toArray
generateToArray(f, i)
// generate fromArray
generateFromArray(f, i)
// generate push
if i < count {
generatePush(f, i)
}
}
return nil
}
func generateTupleMarshal(f *os.File, i int) {
// Create the stringify version
fmt.Fprintf(f, "\n// MarshalJSON marshals the [Tuple%d] into a JSON array\n", i)
fmt.Fprintf(f, "func (t ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") MarshalJSON() ([]byte, error) {\n")
fmt.Fprintf(f, " return tupleMarshalJSON(")
// function prototypes
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t.F%d", j)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
}
func generateTupleUnmarshal(f *os.File, i int) {
// Create the stringify version
fmt.Fprintf(f, "\n// UnmarshalJSON unmarshals a JSON array into a [Tuple%d]\n", i)
fmt.Fprintf(f, "func (t *")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") UnmarshalJSON(data []byte) error {\n")
fmt.Fprintf(f, " return tupleUnmarshalJSON(data")
// function prototypes
for j := 1; j <= i; j++ {
fmt.Fprintf(f, ", &t.F%d", j)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
}
func generateToArray(f *os.File, i int) {
// Create the stringify version
fmt.Fprintf(f, "\n// ToArray converts the [Tuple%d] into an array of type [R] using %d transformation functions from [T] to [R]\n// The inverse function is [FromArray%d]\n", i, i, i)
fmt.Fprintf(f, "func ToArray%d[", i)
// function prototypes
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "F%d ~func(T%d) R", j, j)
}
for j := 1; j <= i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", R any](")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "f%d F%d", j, j)
}
fmt.Fprintf(f, ") func(t ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") []R {\n")
fmt.Fprintf(f, " return func(t ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") []R {\n")
fmt.Fprintf(f, " return []R{\n")
for j := 1; j <= i; j++ {
fmt.Fprintf(f, " f%d(t.F%d),\n", j, j)
}
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, "}\n")
}
func generateFromArray(f *os.File, i int) {
// Create the stringify version
fmt.Fprintf(f, "\n// FromArray converts an array of [R] into a [Tuple%d] using %d functions from [R] to [T]\n// The inverse function is [ToArray%d]\n", i, i, i)
fmt.Fprintf(f, "func FromArray%d[", i)
// function prototypes
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "F%d ~func(R) T%d", j, j)
}
for j := 1; j <= i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", R any](")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "f%d F%d", j, j)
}
fmt.Fprintf(f, ") func(r []R) ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, " {\n")
fmt.Fprintf(f, " return func(r []R) ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, " {\n")
fmt.Fprintf(f, " return MakeTuple%d(\n", i)
for j := 1; j <= i; j++ {
fmt.Fprintf(f, " f%d(r[%d]),\n", j, j-1)
}
fmt.Fprintf(f, " )\n")
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, "}\n")
}
func generateTupleString(f *os.File, i int) {
// Create the stringify version
fmt.Fprintf(f, "\n// String prints some debug info for the [Tuple%d]\n", i)
fmt.Fprintf(f, "func (t ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") String() string {\n")
// convert to string
fmt.Fprint(f, " return tupleString(")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t.F%d", j)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
}
// func generateTupleJson(f *os.File, i int) {
// // Create the stringify version
// fmt.Fprintf(f, "\n// MarshalJSON converts the [Tuple%d] into a JSON byte stream\n", i)
// fmt.Fprintf(f, "func (t ")
// writeTupleType(f, "T", i)
// fmt.Fprintf(f, ") MarshalJSON() ([]byte, error) {\n")
// // convert to string
// fmt.Fprintf(f, " return fmt.Sprintf(\"Tuple%d[", i)
// for j := 1; j <= i; j++ {
// if j > 1 {
// fmt.Fprintf(f, ", ")
// }
// fmt.Fprintf(f, "%s", "%T")
// }
// fmt.Fprintf(f, "](")
// for j := 1; j <= i; j++ {
// if j > 1 {
// fmt.Fprintf(f, ", ")
// }
// fmt.Fprintf(f, "%s", "%v")
// }
// fmt.Fprintf(f, ")\", ")
// for j := 1; j <= i; j++ {
// if j > 1 {
// fmt.Fprintf(f, ", ")
// }
// fmt.Fprintf(f, "t.F%d", j)
// }
// for j := 1; j <= i; j++ {
// fmt.Fprintf(f, ", t.F%d", j)
// }
// fmt.Fprintf(f, ")\n")
// fmt.Fprintf(f, "}\n")
// }
func TupleCommand() *C.Command {
return &C.Command{
Name: "tuple",
Usage: "generate code for Tuple",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateTupleHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

59
v2/constant/const.go Normal file
View 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 constant
import (
F "github.com/IBM/fp-go/v2/function"
M "github.com/IBM/fp-go/v2/monoid"
S "github.com/IBM/fp-go/v2/semigroup"
)
type Const[E, A any] struct {
value E
}
func Make[E, A any](e E) Const[E, A] {
return Const[E, A]{value: e}
}
func Unwrap[E, A any](c Const[E, A]) E {
return c.value
}
func Of[E, A any](m M.Monoid[E]) func(A) Const[E, A] {
return F.Constant1[A](Make[E, A](m.Empty()))
}
func MonadMap[E, A, B any](fa Const[E, A], _ func(A) B) Const[E, B] {
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))
}
}
func Map[E, A, B any](f func(A) B) func(fa Const[E, A]) Const[E, B] {
return F.Bind2nd(MonadMap[E, A, B], f)
}
func Ap[E, A, B any](s S.Semigroup[E]) func(fa Const[E, A]) func(fab Const[E, func(A) B]) Const[E, B] {
monadap := MonadAp[E, A, B](s)
return func(fa Const[E, A]) func(fab Const[E, func(A) B]) Const[E, B] {
return F.Bind2nd(monadap, fa)
}
}

40
v2/constant/const_test.go Normal file
View File

@@ -0,0 +1,40 @@
// 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 constant
import (
"testing"
F "github.com/IBM/fp-go/v2/function"
"github.com/IBM/fp-go/v2/internal/utils"
S "github.com/IBM/fp-go/v2/string"
"github.com/stretchr/testify/assert"
)
func TestMap(t *testing.T) {
fa := Make[string, int]("foo")
assert.Equal(t, fa, F.Pipe1(fa, Map[string, int](utils.Double)))
}
func TestOf(t *testing.T) {
assert.Equal(t, Make[string, int](""), Of[string, int](S.Monoid)(1))
}
func TestAp(t *testing.T) {
fab := Make[string, int]("bar")
assert.Equal(t, Make[string, int]("foobar"), Ap[string, int, int](S.Monoid)(fab)(Make[string, func(int) int]("foo")))
}

View File

@@ -0,0 +1,40 @@
// 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 constraints
type Ordered interface {
Integer | Float | ~string
}
type Signed interface {
~int | ~int8 | ~int16 | ~int32 | ~int64
}
type Unsigned interface {
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
}
type Integer interface {
Signed | Unsigned
}
type Float interface {
~float32 | ~float64
}
type Complex interface {
~complex64 | ~complex128
}

17
v2/context/doc.go Normal file
View File

@@ -0,0 +1,17 @@
// 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 context contains versions of reader IO monads that work with a golang [context.Context]
package context

View File

@@ -0,0 +1,33 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package generic
import (
"context"
E "github.com/IBM/fp-go/v2/either"
IOE "github.com/IBM/fp-go/v2/ioeither/generic"
)
// WithContext wraps an existing IOEither and performs a context check for cancellation before delegating
func WithContext[GIO ~func() E.Either[error, A], A any](ctx context.Context, ma GIO) GIO {
return IOE.MakeIO[GIO](func() E.Either[error, A] {
if err := context.Cause(ctx); err != nil {
return E.Left[A](err)
}
return ma()
})
}

View File

@@ -0,0 +1,28 @@
// 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 ioeither
import (
"context"
G "github.com/IBM/fp-go/v2/context/ioeither/generic"
IOE "github.com/IBM/fp-go/v2/ioeither"
)
// withContext wraps an existing IOEither and performs a context check for cancellation before delegating
func WithContext[A any](ctx context.Context, ma IOE.IOEither[error, A]) IOE.IOEither[error, A] {
return G.WithContext(ctx, ma)
}

View File

@@ -0,0 +1,35 @@
// 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 readereither
import (
RE "github.com/IBM/fp-go/v2/readereither/generic"
)
// TraverseArray transforms an array
func TraverseArray[A, B any](f func(A) ReaderEither[B]) func([]A) ReaderEither[[]B] {
return RE.TraverseArray[ReaderEither[B], ReaderEither[[]B], []A](f)
}
// TraverseArrayWithIndex transforms an array
func TraverseArrayWithIndex[A, B any](f func(int, A) ReaderEither[B]) func([]A) ReaderEither[[]B] {
return RE.TraverseArrayWithIndex[ReaderEither[B], ReaderEither[[]B], []A](f)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[A any](ma []ReaderEither[A]) ReaderEither[[]A] {
return RE.SequenceArray[ReaderEither[A], ReaderEither[[]A]](ma)
}

View File

@@ -0,0 +1,68 @@
// 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 readereither
import (
"context"
G "github.com/IBM/fp-go/v2/readereither/generic"
)
// Bind creates an empty context of type [S] to be used with the [Bind] operation
func Do[S any](
empty S,
) ReaderEither[S] {
return G.Do[ReaderEither[S], context.Context, error, S](empty)
}
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
func Bind[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) ReaderEither[T],
) func(ReaderEither[S1]) ReaderEither[S2] {
return G.Bind[ReaderEither[S1], ReaderEither[S2], ReaderEither[T], context.Context, error, S1, S2, T](setter, f)
}
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
func Let[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) T,
) func(ReaderEither[S1]) ReaderEither[S2] {
return G.Let[ReaderEither[S1], ReaderEither[S2], context.Context, error, S1, S2, T](setter, f)
}
// LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetTo[S1, S2, T any](
setter func(T) func(S1) S2,
b T,
) func(ReaderEither[S1]) ReaderEither[S2] {
return G.LetTo[ReaderEither[S1], ReaderEither[S2], context.Context, error, S1, S2, T](setter, b)
}
// BindTo initializes a new state [S1] from a value [T]
func BindTo[S1, T any](
setter func(T) S1,
) func(ReaderEither[T]) ReaderEither[S1] {
return G.BindTo[ReaderEither[S1], ReaderEither[T], context.Context, error, S1, T](setter)
}
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
func ApS[S1, S2, T any](
setter func(T) func(S1) S2,
fa ReaderEither[T],
) func(ReaderEither[S1]) ReaderEither[S2] {
return G.ApS[ReaderEither[S1], ReaderEither[S2], ReaderEither[T], context.Context, error, S1, S2, T](setter, fa)
}

View File

@@ -0,0 +1,58 @@
// 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 readereither
import (
"context"
"testing"
E "github.com/IBM/fp-go/v2/either"
F "github.com/IBM/fp-go/v2/function"
"github.com/IBM/fp-go/v2/internal/utils"
"github.com/stretchr/testify/assert"
)
func getLastName(s utils.Initial) ReaderEither[string] {
return Of("Doe")
}
func getGivenName(s utils.WithLastName) ReaderEither[string] {
return Of("John")
}
func TestBind(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
Bind(utils.SetLastName, getLastName),
Bind(utils.SetGivenName, getGivenName),
Map(utils.GetFullName),
)
assert.Equal(t, res(context.Background()), E.Of[error]("John Doe"))
}
func TestApS(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
ApS(utils.SetLastName, Of("Doe")),
ApS(utils.SetGivenName, Of("John")),
Map(utils.GetFullName),
)
assert.Equal(t, res(context.Background()), E.Of[error]("John Doe"))
}

View File

@@ -0,0 +1,32 @@
// 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 readereither
import (
"context"
E "github.com/IBM/fp-go/v2/either"
)
// withContext wraps an existing ReaderEither and performs a context check for cancellation before deletating
func WithContext[A any](ma ReaderEither[A]) ReaderEither[A] {
return func(ctx context.Context) E.Either[error, A] {
if err := context.Cause(ctx); err != nil {
return E.Left[A](err)
}
return ma(ctx)
}
}

View File

@@ -0,0 +1,53 @@
// 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 readereither
import (
"context"
RE "github.com/IBM/fp-go/v2/readereither/generic"
)
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
func Curry0[A any](f func(context.Context) (A, error)) ReaderEither[A] {
return RE.Curry0[ReaderEither[A]](f)
}
func Curry1[T1, A any](f func(context.Context, T1) (A, error)) func(T1) ReaderEither[A] {
return RE.Curry1[ReaderEither[A]](f)
}
func Curry2[T1, T2, A any](f func(context.Context, T1, T2) (A, error)) func(T1) func(T2) ReaderEither[A] {
return RE.Curry2[ReaderEither[A]](f)
}
func Curry3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) (A, error)) func(T1) func(T2) func(T3) ReaderEither[A] {
return RE.Curry3[ReaderEither[A]](f)
}
func Uncurry1[T1, A any](f func(T1) ReaderEither[A]) func(context.Context, T1) (A, error) {
return RE.Uncurry1(f)
}
func Uncurry2[T1, T2, A any](f func(T1) func(T2) ReaderEither[A]) func(context.Context, T1, T2) (A, error) {
return RE.Uncurry2(f)
}
func Uncurry3[T1, T2, T3, A any](f func(T1) func(T2) func(T3) ReaderEither[A]) func(context.Context, T1, T2, T3) (A, error) {
return RE.Uncurry3(f)
}

View File

@@ -0,0 +1,39 @@
// 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 exec
import (
"context"
RE "github.com/IBM/fp-go/v2/context/readereither"
E "github.com/IBM/fp-go/v2/either"
"github.com/IBM/fp-go/v2/exec"
F "github.com/IBM/fp-go/v2/function"
GE "github.com/IBM/fp-go/v2/internal/exec"
)
var (
// Command executes a command
// use this version if the command does not produce any side effect, i.e. if the output is uniquely determined by by the input
// typically you'd rather use the ReaderIOEither version of the command
Command = F.Curry3(command)
)
func command(name string, args []string, in []byte) RE.ReaderEither[exec.CommandOutput] {
return func(ctx context.Context) E.Either[error, exec.CommandOutput] {
return E.TryCatchError(GE.Exec(ctx, name, args, in))
}
}

View File

@@ -0,0 +1,41 @@
// 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 readereither
import (
"context"
RE "github.com/IBM/fp-go/v2/readereither/generic"
)
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
func From0[A any](f func(context.Context) (A, error)) func() ReaderEither[A] {
return RE.From0[ReaderEither[A]](f)
}
func From1[T1, A any](f func(context.Context, T1) (A, error)) func(T1) ReaderEither[A] {
return RE.From1[ReaderEither[A]](f)
}
func From2[T1, T2, A any](f func(context.Context, T1, T2) (A, error)) func(T1, T2) ReaderEither[A] {
return RE.From2[ReaderEither[A]](f)
}
func From3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) (A, error)) func(T1, T2, T3) ReaderEither[A] {
return RE.From3[ReaderEither[A]](f)
}

View File

@@ -0,0 +1,100 @@
// 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 readereither
import (
"context"
ET "github.com/IBM/fp-go/v2/either"
O "github.com/IBM/fp-go/v2/option"
RE "github.com/IBM/fp-go/v2/readereither/generic"
)
func MakeReaderEither[A any](f func(context.Context) ET.Either[error, A]) ReaderEither[A] {
return RE.MakeReaderEither[ReaderEither[A]](f)
}
func FromEither[A any](e ET.Either[error, A]) ReaderEither[A] {
return RE.FromEither[ReaderEither[A]](e)
}
func Left[A any](l error) ReaderEither[A] {
return RE.Left[ReaderEither[A]](l)
}
func Right[A any](r A) ReaderEither[A] {
return RE.Right[ReaderEither[A]](r)
}
func MonadMap[A, B any](fa ReaderEither[A], f func(A) B) ReaderEither[B] {
return RE.MonadMap[ReaderEither[A], ReaderEither[B]](fa, f)
}
func Map[A, B any](f func(A) B) func(ReaderEither[A]) ReaderEither[B] {
return RE.Map[ReaderEither[A], ReaderEither[B]](f)
}
func MonadChain[A, B any](ma ReaderEither[A], f func(A) ReaderEither[B]) ReaderEither[B] {
return RE.MonadChain(ma, f)
}
func Chain[A, B any](f func(A) ReaderEither[B]) func(ReaderEither[A]) ReaderEither[B] {
return RE.Chain[ReaderEither[A]](f)
}
func Of[A any](a A) ReaderEither[A] {
return RE.Of[ReaderEither[A]](a)
}
func MonadAp[A, B any](fab ReaderEither[func(A) B], fa ReaderEither[A]) ReaderEither[B] {
return RE.MonadAp[ReaderEither[A], ReaderEither[B]](fab, fa)
}
func Ap[A, B any](fa ReaderEither[A]) func(ReaderEither[func(A) B]) ReaderEither[B] {
return RE.Ap[ReaderEither[A], ReaderEither[B], ReaderEither[func(A) B]](fa)
}
func FromPredicate[A any](pred func(A) bool, onFalse func(A) error) func(A) ReaderEither[A] {
return RE.FromPredicate[ReaderEither[A]](pred, onFalse)
}
func OrElse[A any](onLeft func(error) ReaderEither[A]) func(ReaderEither[A]) ReaderEither[A] {
return RE.OrElse[ReaderEither[A]](onLeft)
}
func Ask() ReaderEither[context.Context] {
return RE.Ask[ReaderEither[context.Context]]()
}
func MonadChainEitherK[A, B any](ma ReaderEither[A], f func(A) ET.Either[error, B]) ReaderEither[B] {
return RE.MonadChainEitherK[ReaderEither[A], ReaderEither[B]](ma, f)
}
func ChainEitherK[A, B any](f func(A) ET.Either[error, B]) func(ma ReaderEither[A]) ReaderEither[B] {
return RE.ChainEitherK[ReaderEither[A], ReaderEither[B]](f)
}
func ChainOptionK[A, B any](onNone func() error) func(func(A) O.Option[B]) func(ReaderEither[A]) ReaderEither[B] {
return RE.ChainOptionK[ReaderEither[A], ReaderEither[B]](onNone)
}
func MonadFlap[B, A any](fab ReaderEither[func(A) B], a A) ReaderEither[B] {
return RE.MonadFlap[ReaderEither[func(A) B], ReaderEither[B]](fab, a)
}
func Flap[B, A any](a A) func(ReaderEither[func(A) B]) ReaderEither[B] {
return RE.Flap[ReaderEither[func(A) B], ReaderEither[B]](a)
}

View File

@@ -0,0 +1,57 @@
// 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 readereither
import (
RE "github.com/IBM/fp-go/v2/readereither/generic"
T "github.com/IBM/fp-go/v2/tuple"
)
// SequenceT converts n inputs of higher kinded types into a higher kinded types of n strongly typed values, represented as a tuple
func SequenceT1[A any](a ReaderEither[A]) ReaderEither[T.Tuple1[A]] {
return RE.SequenceT1[
ReaderEither[A],
ReaderEither[T.Tuple1[A]],
](a)
}
func SequenceT2[A, B any](a ReaderEither[A], b ReaderEither[B]) ReaderEither[T.Tuple2[A, B]] {
return RE.SequenceT2[
ReaderEither[A],
ReaderEither[B],
ReaderEither[T.Tuple2[A, B]],
](a, b)
}
func SequenceT3[A, B, C any](a ReaderEither[A], b ReaderEither[B], c ReaderEither[C]) ReaderEither[T.Tuple3[A, B, C]] {
return RE.SequenceT3[
ReaderEither[A],
ReaderEither[B],
ReaderEither[C],
ReaderEither[T.Tuple3[A, B, C]],
](a, b, c)
}
func SequenceT4[A, B, C, D any](a ReaderEither[A], b ReaderEither[B], c ReaderEither[C], d ReaderEither[D]) ReaderEither[T.Tuple4[A, B, C, D]] {
return RE.SequenceT4[
ReaderEither[A],
ReaderEither[B],
ReaderEither[C],
ReaderEither[D],
ReaderEither[T.Tuple4[A, B, C, D]],
](a, b, c, d)
}

View 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 readereither implements a specialization of the Reader monad assuming a golang context as the context of the monad and a standard golang error
package readereither
import (
"context"
RE "github.com/IBM/fp-go/v2/readereither"
)
// ReaderEither is a specialization of the Reader monad for the typical golang scenario
type ReaderEither[A any] RE.ReaderEither[context.Context, error, A]

View File

@@ -0,0 +1,67 @@
// 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 readerioeither
import (
G "github.com/IBM/fp-go/v2/context/readerioeither/generic"
IOE "github.com/IBM/fp-go/v2/ioeither"
)
// Bind creates an empty context of type [S] to be used with the [Bind] operation
func Do[S any](
empty S,
) ReaderIOEither[S] {
return G.Do[ReaderIOEither[S], IOE.IOEither[error, S], S](empty)
}
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
func Bind[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) ReaderIOEither[T],
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
return G.Bind[ReaderIOEither[S1], ReaderIOEither[S2], ReaderIOEither[T], IOE.IOEither[error, S1], IOE.IOEither[error, S2], IOE.IOEither[error, T], S1, S2, T](setter, f)
}
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
func Let[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) T,
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
return G.Let[ReaderIOEither[S1], ReaderIOEither[S2], IOE.IOEither[error, S1], IOE.IOEither[error, S2], S1, S2, T](setter, f)
}
// LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetTo[S1, S2, T any](
setter func(T) func(S1) S2,
b T,
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
return G.LetTo[ReaderIOEither[S1], ReaderIOEither[S2], IOE.IOEither[error, S1], IOE.IOEither[error, S2], S1, S2, T](setter, b)
}
// BindTo initializes a new state [S1] from a value [T]
func BindTo[S1, T any](
setter func(T) S1,
) func(ReaderIOEither[T]) ReaderIOEither[S1] {
return G.BindTo[ReaderIOEither[S1], ReaderIOEither[T], IOE.IOEither[error, S1], IOE.IOEither[error, T], S1, T](setter)
}
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
func ApS[S1, S2, T any](
setter func(T) func(S1) S2,
fa ReaderIOEither[T],
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
return G.ApS[ReaderIOEither[func(T) S2], ReaderIOEither[S1], ReaderIOEither[S2], ReaderIOEither[T], IOE.IOEither[error, func(T) S2], IOE.IOEither[error, S1], IOE.IOEither[error, S2], IOE.IOEither[error, T], S1, S2, T](setter, fa)
}

View File

@@ -0,0 +1,58 @@
// 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 readerioeither
import (
"context"
"testing"
E "github.com/IBM/fp-go/v2/either"
F "github.com/IBM/fp-go/v2/function"
"github.com/IBM/fp-go/v2/internal/utils"
"github.com/stretchr/testify/assert"
)
func getLastName(s utils.Initial) ReaderIOEither[string] {
return Of("Doe")
}
func getGivenName(s utils.WithLastName) ReaderIOEither[string] {
return Of("John")
}
func TestBind(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
Bind(utils.SetLastName, getLastName),
Bind(utils.SetGivenName, getGivenName),
Map(utils.GetFullName),
)
assert.Equal(t, res(context.Background())(), E.Of[error]("John Doe"))
}
func TestApS(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
ApS(utils.SetLastName, Of("Doe")),
ApS(utils.SetGivenName, Of("John")),
Map(utils.GetFullName),
)
assert.Equal(t, res(context.Background())(), E.Of[error]("John Doe"))
}

View File

@@ -0,0 +1,37 @@
// 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 readerioeither
import (
G "github.com/IBM/fp-go/v2/context/readerioeither/generic"
E "github.com/IBM/fp-go/v2/either"
)
// Bracket makes sure that a resource is cleaned up in the event of an error. The release action is called regardless of
// whether the body action returns and error or not.
func Bracket[
A, B, ANY any](
acquire ReaderIOEither[A],
use func(A) ReaderIOEither[B],
release func(A, E.Either[error, B]) ReaderIOEither[ANY],
) ReaderIOEither[B] {
return G.Bracket[ReaderIOEither[A], ReaderIOEither[B], ReaderIOEither[ANY]](
acquire,
use,
release,
)
}

View 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 readerioeither
import (
G "github.com/IBM/fp-go/v2/context/readerioeither/generic"
)
// WithContext wraps an existing [ReaderIOEither] and performs a context check for cancellation before delegating
func WithContext[A any](ma ReaderIOEither[A]) ReaderIOEither[A] {
return G.WithContext(ma)
}

View File

@@ -0,0 +1 @@
Carsten

View File

@@ -0,0 +1,19 @@
// 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 readerioeither contains a version of [ReaderIOEither] that takes a golang [context.Context] as its context and that assumes the standard go error
package readerioeither
//go:generate go run ../.. contextreaderioeither --count 10 --filename gen.go

View File

@@ -0,0 +1,29 @@
// 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 readerioeither
import (
"context"
G "github.com/IBM/fp-go/v2/context/readerioeither/generic"
ET "github.com/IBM/fp-go/v2/either"
EQ "github.com/IBM/fp-go/v2/eq"
)
// Eq implements the equals predicate for values contained in the [ReaderIOEither] monad
func Eq[A any](eq EQ.Eq[ET.Either[error, A]]) func(context.Context) EQ.Eq[ReaderIOEither[A]] {
return G.Eq[ReaderIOEither[A]](eq)
}

View File

@@ -0,0 +1,39 @@
// 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 exec
import (
"context"
RIOE "github.com/IBM/fp-go/v2/context/readerioeither"
"github.com/IBM/fp-go/v2/exec"
F "github.com/IBM/fp-go/v2/function"
GE "github.com/IBM/fp-go/v2/internal/exec"
IOE "github.com/IBM/fp-go/v2/ioeither"
)
var (
// Command executes a cancelable command
Command = F.Curry3(command)
)
func command(name string, args []string, in []byte) RIOE.ReaderIOEither[exec.CommandOutput] {
return func(ctx context.Context) IOE.IOEither[error, exec.CommandOutput] {
return IOE.TryCatchError(func() (exec.CommandOutput, error) {
return GE.Exec(ctx, name, args, in)
})
}
}

View File

@@ -0,0 +1,3 @@
{
"data": "Carsten"
}

View 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 file
import (
"context"
"io"
"os"
RIOE "github.com/IBM/fp-go/v2/context/readerioeither"
ET "github.com/IBM/fp-go/v2/either"
F "github.com/IBM/fp-go/v2/function"
"github.com/IBM/fp-go/v2/internal/file"
IOE "github.com/IBM/fp-go/v2/ioeither"
IOEF "github.com/IBM/fp-go/v2/ioeither/file"
)
var (
// Open opens a file for reading within the given context
Open = F.Flow3(
IOEF.Open,
RIOE.FromIOEither[*os.File],
RIOE.WithContext[*os.File],
)
// Remove removes a file by name
Remove = F.Flow2(
IOEF.Remove,
RIOE.FromIOEither[string],
)
)
// Close closes an object
func Close[C io.Closer](c C) RIOE.ReaderIOEither[any] {
return F.Pipe2(
c,
IOEF.Close[C],
RIOE.FromIOEither[any],
)
}
// ReadFile reads a file in the scope of a context
func ReadFile(path string) RIOE.ReaderIOEither[[]byte] {
return RIOE.WithResource[[]byte](Open(path), Close[*os.File])(func(r *os.File) RIOE.ReaderIOEither[[]byte] {
return func(ctx context.Context) IOE.IOEither[error, []byte] {
return IOE.MakeIO(func() ET.Either[error, []byte] {
return file.ReadAll(ctx, r)
})
}
})
}

View 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 file
import (
"context"
"fmt"
R "github.com/IBM/fp-go/v2/context/readerioeither"
F "github.com/IBM/fp-go/v2/function"
IO "github.com/IBM/fp-go/v2/io"
J "github.com/IBM/fp-go/v2/json"
)
type RecordType struct {
Data string `json:"data"`
}
func getData(r RecordType) string {
return r.Data
}
func ExampleReadFile() {
data := F.Pipe3(
ReadFile("./data/file.json"),
R.ChainEitherK(J.Unmarshal[RecordType]),
R.ChainFirstIOK(IO.Logf[RecordType]("Log: %v")),
R.Map(getData),
)
result := data(context.Background())
fmt.Println(result())
// Output:
// Right[string](Carsten)
}

View File

@@ -0,0 +1,52 @@
// 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 file
import (
"os"
RIOE "github.com/IBM/fp-go/v2/context/readerioeither"
F "github.com/IBM/fp-go/v2/function"
IO "github.com/IBM/fp-go/v2/io"
IOF "github.com/IBM/fp-go/v2/io/file"
IOEF "github.com/IBM/fp-go/v2/ioeither/file"
)
var (
// onCreateTempFile creates a temp file with sensible defaults
onCreateTempFile = CreateTemp("", "*")
// destroy handler
onReleaseTempFile = F.Flow4(
IOF.Close[*os.File],
IO.Map((*os.File).Name),
RIOE.FromIO[string],
RIOE.Chain(Remove),
)
)
// CreateTemp created a temp file with proper parametrization
func CreateTemp(dir, pattern string) RIOE.ReaderIOEither[*os.File] {
return F.Pipe2(
IOEF.CreateTemp(dir, pattern),
RIOE.FromIOEither[*os.File],
RIOE.WithContext[*os.File],
)
}
// WithTempFile creates a temporary file, then invokes a callback to create a resource based on the file, then close and remove the temp file
func WithTempFile[A any](f func(*os.File) RIOE.ReaderIOEither[A]) RIOE.ReaderIOEither[A] {
return RIOE.WithResource[A](onCreateTempFile, onReleaseTempFile)(f)
}

View File

@@ -0,0 +1,47 @@
// 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 file
import (
"context"
"os"
"testing"
RIOE "github.com/IBM/fp-go/v2/context/readerioeither"
E "github.com/IBM/fp-go/v2/either"
F "github.com/IBM/fp-go/v2/function"
"github.com/stretchr/testify/assert"
)
func TestWithTempFile(t *testing.T) {
res := WithTempFile(onWriteAll[*os.File]([]byte("Carsten")))
assert.Equal(t, E.Of[error]([]byte("Carsten")), res(context.Background())())
}
func TestWithTempFileOnClosedFile(t *testing.T) {
res := WithTempFile(func(f *os.File) RIOE.ReaderIOEither[[]byte] {
return F.Pipe2(
f,
onWriteAll[*os.File]([]byte("Carsten")),
RIOE.ChainFirst(F.Constant1[[]byte](Close(f))),
)
})
assert.Equal(t, E.Of[error]([]byte("Carsten")), res(context.Background())())
}

View File

@@ -0,0 +1,57 @@
// 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 file
import (
"context"
"io"
RIOE "github.com/IBM/fp-go/v2/context/readerioeither"
F "github.com/IBM/fp-go/v2/function"
)
func onWriteAll[W io.Writer](data []byte) func(w W) RIOE.ReaderIOEither[[]byte] {
return func(w W) RIOE.ReaderIOEither[[]byte] {
return F.Pipe1(
RIOE.TryCatch(func(_ context.Context) func() ([]byte, error) {
return func() ([]byte, error) {
_, err := w.Write(data)
return data, err
}
}),
RIOE.WithContext[[]byte],
)
}
}
// WriteAll uses a generator function to create a stream, writes data to it and closes it
func WriteAll[W io.WriteCloser](data []byte) func(acquire RIOE.ReaderIOEither[W]) RIOE.ReaderIOEither[[]byte] {
onWrite := onWriteAll[W](data)
return func(onCreate RIOE.ReaderIOEither[W]) RIOE.ReaderIOEither[[]byte] {
return RIOE.WithResource[[]byte](
onCreate,
Close[W])(
onWrite,
)
}
}
// Write uses a generator function to create a stream, writes data to it and closes it
func Write[R any, W io.WriteCloser](acquire RIOE.ReaderIOEither[W]) func(use func(W) RIOE.ReaderIOEither[R]) RIOE.ReaderIOEither[R] {
return RIOE.WithResource[R](
acquire,
Close[W])
}

View File

@@ -0,0 +1,594 @@
package readerioeither
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2024-05-24 22:24:01.4250895 +0200 CEST m=+0.014515801
import (
"context"
G "github.com/IBM/fp-go/v2/context/readerioeither/generic"
T "github.com/IBM/fp-go/v2/tuple"
)
// Eitherize0 converts a function with 0 parameters returning a tuple into a function with 0 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize0]
func Eitherize0[F ~func(context.Context) (R, error), R any](f F) func() ReaderIOEither[R] {
return G.Eitherize0[ReaderIOEither[R]](f)
}
// Uneitherize0 converts a function with 1 parameters returning a [ReaderIOEither[R]] into a function with 0 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize0[F ~func() ReaderIOEither[R], R any](f F) func(context.Context) (R, error) {
return G.Uneitherize0[ReaderIOEither[R], func(context.Context) (R, error)](f)
}
// Eitherize1 converts a function with 1 parameters returning a tuple into a function with 1 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize1]
func Eitherize1[F ~func(context.Context, T0) (R, error), T0, R any](f F) func(T0) ReaderIOEither[R] {
return G.Eitherize1[ReaderIOEither[R]](f)
}
// Uneitherize1 converts a function with 2 parameters returning a [ReaderIOEither[R]] into a function with 1 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize1[F ~func(T0) ReaderIOEither[R], T0, R any](f F) func(context.Context, T0) (R, error) {
return G.Uneitherize1[ReaderIOEither[R], func(context.Context, T0) (R, error)](f)
}
// SequenceT1 converts 1 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func SequenceT1[T1 any](t1 ReaderIOEither[T1]) ReaderIOEither[T.Tuple1[T1]] {
return G.SequenceT1[ReaderIOEither[T.Tuple1[T1]]](t1)
}
// SequenceSeqT1 converts 1 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func SequenceSeqT1[T1 any](t1 ReaderIOEither[T1]) ReaderIOEither[T.Tuple1[T1]] {
return G.SequenceSeqT1[ReaderIOEither[T.Tuple1[T1]]](t1)
}
// SequenceParT1 converts 1 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func SequenceParT1[T1 any](t1 ReaderIOEither[T1]) ReaderIOEither[T.Tuple1[T1]] {
return G.SequenceParT1[ReaderIOEither[T.Tuple1[T1]]](t1)
}
// SequenceTuple1 converts a [T.Tuple1] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func SequenceTuple1[T1 any](t T.Tuple1[ReaderIOEither[T1]]) ReaderIOEither[T.Tuple1[T1]] {
return G.SequenceTuple1[ReaderIOEither[T.Tuple1[T1]]](t)
}
// SequenceSeqTuple1 converts a [T.Tuple1] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func SequenceSeqTuple1[T1 any](t T.Tuple1[ReaderIOEither[T1]]) ReaderIOEither[T.Tuple1[T1]] {
return G.SequenceSeqTuple1[ReaderIOEither[T.Tuple1[T1]]](t)
}
// SequenceParTuple1 converts a [T.Tuple1] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func SequenceParTuple1[T1 any](t T.Tuple1[ReaderIOEither[T1]]) ReaderIOEither[T.Tuple1[T1]] {
return G.SequenceParTuple1[ReaderIOEither[T.Tuple1[T1]]](t)
}
// TraverseTuple1 converts a [T.Tuple1] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func TraverseTuple1[F1 ~func(A1) ReaderIOEither[T1], A1, T1 any](f1 F1) func(T.Tuple1[A1]) ReaderIOEither[T.Tuple1[T1]] {
return G.TraverseTuple1[ReaderIOEither[T.Tuple1[T1]]](f1)
}
// TraverseSeqTuple1 converts a [T.Tuple1] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func TraverseSeqTuple1[F1 ~func(A1) ReaderIOEither[T1], A1, T1 any](f1 F1) func(T.Tuple1[A1]) ReaderIOEither[T.Tuple1[T1]] {
return G.TraverseSeqTuple1[ReaderIOEither[T.Tuple1[T1]]](f1)
}
// TraverseParTuple1 converts a [T.Tuple1] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func TraverseParTuple1[F1 ~func(A1) ReaderIOEither[T1], A1, T1 any](f1 F1) func(T.Tuple1[A1]) ReaderIOEither[T.Tuple1[T1]] {
return G.TraverseParTuple1[ReaderIOEither[T.Tuple1[T1]]](f1)
}
// Eitherize2 converts a function with 2 parameters returning a tuple into a function with 2 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize2]
func Eitherize2[F ~func(context.Context, T0, T1) (R, error), T0, T1, R any](f F) func(T0, T1) ReaderIOEither[R] {
return G.Eitherize2[ReaderIOEither[R]](f)
}
// Uneitherize2 converts a function with 3 parameters returning a [ReaderIOEither[R]] into a function with 2 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize2[F ~func(T0, T1) ReaderIOEither[R], T0, T1, R any](f F) func(context.Context, T0, T1) (R, error) {
return G.Uneitherize2[ReaderIOEither[R], func(context.Context, T0, T1) (R, error)](f)
}
// SequenceT2 converts 2 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func SequenceT2[T1, T2 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.SequenceT2[ReaderIOEither[T.Tuple2[T1, T2]]](t1, t2)
}
// SequenceSeqT2 converts 2 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func SequenceSeqT2[T1, T2 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.SequenceSeqT2[ReaderIOEither[T.Tuple2[T1, T2]]](t1, t2)
}
// SequenceParT2 converts 2 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func SequenceParT2[T1, T2 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.SequenceParT2[ReaderIOEither[T.Tuple2[T1, T2]]](t1, t2)
}
// SequenceTuple2 converts a [T.Tuple2] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func SequenceTuple2[T1, T2 any](t T.Tuple2[ReaderIOEither[T1], ReaderIOEither[T2]]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.SequenceTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](t)
}
// SequenceSeqTuple2 converts a [T.Tuple2] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func SequenceSeqTuple2[T1, T2 any](t T.Tuple2[ReaderIOEither[T1], ReaderIOEither[T2]]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.SequenceSeqTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](t)
}
// SequenceParTuple2 converts a [T.Tuple2] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func SequenceParTuple2[T1, T2 any](t T.Tuple2[ReaderIOEither[T1], ReaderIOEither[T2]]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.SequenceParTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](t)
}
// TraverseTuple2 converts a [T.Tuple2] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func TraverseTuple2[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], A1, T1, A2, T2 any](f1 F1, f2 F2) func(T.Tuple2[A1, A2]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.TraverseTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](f1, f2)
}
// TraverseSeqTuple2 converts a [T.Tuple2] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func TraverseSeqTuple2[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], A1, T1, A2, T2 any](f1 F1, f2 F2) func(T.Tuple2[A1, A2]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.TraverseSeqTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](f1, f2)
}
// TraverseParTuple2 converts a [T.Tuple2] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func TraverseParTuple2[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], A1, T1, A2, T2 any](f1 F1, f2 F2) func(T.Tuple2[A1, A2]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.TraverseParTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](f1, f2)
}
// Eitherize3 converts a function with 3 parameters returning a tuple into a function with 3 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize3]
func Eitherize3[F ~func(context.Context, T0, T1, T2) (R, error), T0, T1, T2, R any](f F) func(T0, T1, T2) ReaderIOEither[R] {
return G.Eitherize3[ReaderIOEither[R]](f)
}
// Uneitherize3 converts a function with 4 parameters returning a [ReaderIOEither[R]] into a function with 3 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize3[F ~func(T0, T1, T2) ReaderIOEither[R], T0, T1, T2, R any](f F) func(context.Context, T0, T1, T2) (R, error) {
return G.Uneitherize3[ReaderIOEither[R], func(context.Context, T0, T1, T2) (R, error)](f)
}
// SequenceT3 converts 3 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func SequenceT3[T1, T2, T3 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.SequenceT3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t1, t2, t3)
}
// SequenceSeqT3 converts 3 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func SequenceSeqT3[T1, T2, T3 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.SequenceSeqT3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t1, t2, t3)
}
// SequenceParT3 converts 3 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func SequenceParT3[T1, T2, T3 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.SequenceParT3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t1, t2, t3)
}
// SequenceTuple3 converts a [T.Tuple3] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func SequenceTuple3[T1, T2, T3 any](t T.Tuple3[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3]]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.SequenceTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t)
}
// SequenceSeqTuple3 converts a [T.Tuple3] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func SequenceSeqTuple3[T1, T2, T3 any](t T.Tuple3[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3]]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.SequenceSeqTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t)
}
// SequenceParTuple3 converts a [T.Tuple3] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func SequenceParTuple3[T1, T2, T3 any](t T.Tuple3[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3]]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.SequenceParTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t)
}
// TraverseTuple3 converts a [T.Tuple3] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func TraverseTuple3[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], A1, T1, A2, T2, A3, T3 any](f1 F1, f2 F2, f3 F3) func(T.Tuple3[A1, A2, A3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.TraverseTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](f1, f2, f3)
}
// TraverseSeqTuple3 converts a [T.Tuple3] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func TraverseSeqTuple3[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], A1, T1, A2, T2, A3, T3 any](f1 F1, f2 F2, f3 F3) func(T.Tuple3[A1, A2, A3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.TraverseSeqTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](f1, f2, f3)
}
// TraverseParTuple3 converts a [T.Tuple3] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func TraverseParTuple3[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], A1, T1, A2, T2, A3, T3 any](f1 F1, f2 F2, f3 F3) func(T.Tuple3[A1, A2, A3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.TraverseParTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](f1, f2, f3)
}
// Eitherize4 converts a function with 4 parameters returning a tuple into a function with 4 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize4]
func Eitherize4[F ~func(context.Context, T0, T1, T2, T3) (R, error), T0, T1, T2, T3, R any](f F) func(T0, T1, T2, T3) ReaderIOEither[R] {
return G.Eitherize4[ReaderIOEither[R]](f)
}
// Uneitherize4 converts a function with 5 parameters returning a [ReaderIOEither[R]] into a function with 4 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize4[F ~func(T0, T1, T2, T3) ReaderIOEither[R], T0, T1, T2, T3, R any](f F) func(context.Context, T0, T1, T2, T3) (R, error) {
return G.Uneitherize4[ReaderIOEither[R], func(context.Context, T0, T1, T2, T3) (R, error)](f)
}
// SequenceT4 converts 4 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func SequenceT4[T1, T2, T3, T4 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.SequenceT4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t1, t2, t3, t4)
}
// SequenceSeqT4 converts 4 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func SequenceSeqT4[T1, T2, T3, T4 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.SequenceSeqT4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t1, t2, t3, t4)
}
// SequenceParT4 converts 4 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func SequenceParT4[T1, T2, T3, T4 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.SequenceParT4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t1, t2, t3, t4)
}
// SequenceTuple4 converts a [T.Tuple4] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func SequenceTuple4[T1, T2, T3, T4 any](t T.Tuple4[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4]]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.SequenceTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t)
}
// SequenceSeqTuple4 converts a [T.Tuple4] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func SequenceSeqTuple4[T1, T2, T3, T4 any](t T.Tuple4[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4]]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.SequenceSeqTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t)
}
// SequenceParTuple4 converts a [T.Tuple4] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func SequenceParTuple4[T1, T2, T3, T4 any](t T.Tuple4[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4]]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.SequenceParTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t)
}
// TraverseTuple4 converts a [T.Tuple4] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func TraverseTuple4[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], A1, T1, A2, T2, A3, T3, A4, T4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(T.Tuple4[A1, A2, A3, A4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.TraverseTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](f1, f2, f3, f4)
}
// TraverseSeqTuple4 converts a [T.Tuple4] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func TraverseSeqTuple4[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], A1, T1, A2, T2, A3, T3, A4, T4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(T.Tuple4[A1, A2, A3, A4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.TraverseSeqTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](f1, f2, f3, f4)
}
// TraverseParTuple4 converts a [T.Tuple4] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func TraverseParTuple4[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], A1, T1, A2, T2, A3, T3, A4, T4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(T.Tuple4[A1, A2, A3, A4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.TraverseParTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](f1, f2, f3, f4)
}
// Eitherize5 converts a function with 5 parameters returning a tuple into a function with 5 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize5]
func Eitherize5[F ~func(context.Context, T0, T1, T2, T3, T4) (R, error), T0, T1, T2, T3, T4, R any](f F) func(T0, T1, T2, T3, T4) ReaderIOEither[R] {
return G.Eitherize5[ReaderIOEither[R]](f)
}
// Uneitherize5 converts a function with 6 parameters returning a [ReaderIOEither[R]] into a function with 5 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize5[F ~func(T0, T1, T2, T3, T4) ReaderIOEither[R], T0, T1, T2, T3, T4, R any](f F) func(context.Context, T0, T1, T2, T3, T4) (R, error) {
return G.Uneitherize5[ReaderIOEither[R], func(context.Context, T0, T1, T2, T3, T4) (R, error)](f)
}
// SequenceT5 converts 5 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func SequenceT5[T1, T2, T3, T4, T5 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.SequenceT5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t1, t2, t3, t4, t5)
}
// SequenceSeqT5 converts 5 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func SequenceSeqT5[T1, T2, T3, T4, T5 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.SequenceSeqT5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t1, t2, t3, t4, t5)
}
// SequenceParT5 converts 5 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func SequenceParT5[T1, T2, T3, T4, T5 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.SequenceParT5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t1, t2, t3, t4, t5)
}
// SequenceTuple5 converts a [T.Tuple5] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func SequenceTuple5[T1, T2, T3, T4, T5 any](t T.Tuple5[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5]]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.SequenceTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t)
}
// SequenceSeqTuple5 converts a [T.Tuple5] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func SequenceSeqTuple5[T1, T2, T3, T4, T5 any](t T.Tuple5[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5]]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.SequenceSeqTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t)
}
// SequenceParTuple5 converts a [T.Tuple5] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func SequenceParTuple5[T1, T2, T3, T4, T5 any](t T.Tuple5[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5]]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.SequenceParTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t)
}
// TraverseTuple5 converts a [T.Tuple5] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func TraverseTuple5[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(T.Tuple5[A1, A2, A3, A4, A5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.TraverseTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](f1, f2, f3, f4, f5)
}
// TraverseSeqTuple5 converts a [T.Tuple5] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func TraverseSeqTuple5[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(T.Tuple5[A1, A2, A3, A4, A5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.TraverseSeqTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](f1, f2, f3, f4, f5)
}
// TraverseParTuple5 converts a [T.Tuple5] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func TraverseParTuple5[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(T.Tuple5[A1, A2, A3, A4, A5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.TraverseParTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](f1, f2, f3, f4, f5)
}
// Eitherize6 converts a function with 6 parameters returning a tuple into a function with 6 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize6]
func Eitherize6[F ~func(context.Context, T0, T1, T2, T3, T4, T5) (R, error), T0, T1, T2, T3, T4, T5, R any](f F) func(T0, T1, T2, T3, T4, T5) ReaderIOEither[R] {
return G.Eitherize6[ReaderIOEither[R]](f)
}
// Uneitherize6 converts a function with 7 parameters returning a [ReaderIOEither[R]] into a function with 6 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize6[F ~func(T0, T1, T2, T3, T4, T5) ReaderIOEither[R], T0, T1, T2, T3, T4, T5, R any](f F) func(context.Context, T0, T1, T2, T3, T4, T5) (R, error) {
return G.Uneitherize6[ReaderIOEither[R], func(context.Context, T0, T1, T2, T3, T4, T5) (R, error)](f)
}
// SequenceT6 converts 6 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func SequenceT6[T1, T2, T3, T4, T5, T6 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.SequenceT6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t1, t2, t3, t4, t5, t6)
}
// SequenceSeqT6 converts 6 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func SequenceSeqT6[T1, T2, T3, T4, T5, T6 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.SequenceSeqT6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t1, t2, t3, t4, t5, t6)
}
// SequenceParT6 converts 6 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func SequenceParT6[T1, T2, T3, T4, T5, T6 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.SequenceParT6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t1, t2, t3, t4, t5, t6)
}
// SequenceTuple6 converts a [T.Tuple6] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func SequenceTuple6[T1, T2, T3, T4, T5, T6 any](t T.Tuple6[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6]]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.SequenceTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t)
}
// SequenceSeqTuple6 converts a [T.Tuple6] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func SequenceSeqTuple6[T1, T2, T3, T4, T5, T6 any](t T.Tuple6[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6]]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.SequenceSeqTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t)
}
// SequenceParTuple6 converts a [T.Tuple6] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func SequenceParTuple6[T1, T2, T3, T4, T5, T6 any](t T.Tuple6[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6]]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.SequenceParTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t)
}
// TraverseTuple6 converts a [T.Tuple6] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func TraverseTuple6[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(T.Tuple6[A1, A2, A3, A4, A5, A6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.TraverseTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](f1, f2, f3, f4, f5, f6)
}
// TraverseSeqTuple6 converts a [T.Tuple6] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func TraverseSeqTuple6[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(T.Tuple6[A1, A2, A3, A4, A5, A6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.TraverseSeqTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](f1, f2, f3, f4, f5, f6)
}
// TraverseParTuple6 converts a [T.Tuple6] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func TraverseParTuple6[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(T.Tuple6[A1, A2, A3, A4, A5, A6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.TraverseParTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](f1, f2, f3, f4, f5, f6)
}
// Eitherize7 converts a function with 7 parameters returning a tuple into a function with 7 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize7]
func Eitherize7[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6) (R, error), T0, T1, T2, T3, T4, T5, T6, R any](f F) func(T0, T1, T2, T3, T4, T5, T6) ReaderIOEither[R] {
return G.Eitherize7[ReaderIOEither[R]](f)
}
// Uneitherize7 converts a function with 8 parameters returning a [ReaderIOEither[R]] into a function with 7 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize7[F ~func(T0, T1, T2, T3, T4, T5, T6) ReaderIOEither[R], T0, T1, T2, T3, T4, T5, T6, R any](f F) func(context.Context, T0, T1, T2, T3, T4, T5, T6) (R, error) {
return G.Uneitherize7[ReaderIOEither[R], func(context.Context, T0, T1, T2, T3, T4, T5, T6) (R, error)](f)
}
// SequenceT7 converts 7 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func SequenceT7[T1, T2, T3, T4, T5, T6, T7 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.SequenceT7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t1, t2, t3, t4, t5, t6, t7)
}
// SequenceSeqT7 converts 7 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func SequenceSeqT7[T1, T2, T3, T4, T5, T6, T7 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.SequenceSeqT7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t1, t2, t3, t4, t5, t6, t7)
}
// SequenceParT7 converts 7 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func SequenceParT7[T1, T2, T3, T4, T5, T6, T7 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.SequenceParT7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t1, t2, t3, t4, t5, t6, t7)
}
// SequenceTuple7 converts a [T.Tuple7] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func SequenceTuple7[T1, T2, T3, T4, T5, T6, T7 any](t T.Tuple7[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7]]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.SequenceTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t)
}
// SequenceSeqTuple7 converts a [T.Tuple7] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func SequenceSeqTuple7[T1, T2, T3, T4, T5, T6, T7 any](t T.Tuple7[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7]]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.SequenceSeqTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t)
}
// SequenceParTuple7 converts a [T.Tuple7] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func SequenceParTuple7[T1, T2, T3, T4, T5, T6, T7 any](t T.Tuple7[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7]]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.SequenceParTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t)
}
// TraverseTuple7 converts a [T.Tuple7] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func TraverseTuple7[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) func(T.Tuple7[A1, A2, A3, A4, A5, A6, A7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.TraverseTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](f1, f2, f3, f4, f5, f6, f7)
}
// TraverseSeqTuple7 converts a [T.Tuple7] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func TraverseSeqTuple7[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) func(T.Tuple7[A1, A2, A3, A4, A5, A6, A7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.TraverseSeqTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](f1, f2, f3, f4, f5, f6, f7)
}
// TraverseParTuple7 converts a [T.Tuple7] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func TraverseParTuple7[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) func(T.Tuple7[A1, A2, A3, A4, A5, A6, A7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.TraverseParTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](f1, f2, f3, f4, f5, f6, f7)
}
// Eitherize8 converts a function with 8 parameters returning a tuple into a function with 8 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize8]
func Eitherize8[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7) ReaderIOEither[R] {
return G.Eitherize8[ReaderIOEither[R]](f)
}
// Uneitherize8 converts a function with 9 parameters returning a [ReaderIOEither[R]] into a function with 8 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize8[F ~func(T0, T1, T2, T3, T4, T5, T6, T7) ReaderIOEither[R], T0, T1, T2, T3, T4, T5, T6, T7, R any](f F) func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7) (R, error) {
return G.Uneitherize8[ReaderIOEither[R], func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7) (R, error)](f)
}
// SequenceT8 converts 8 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func SequenceT8[T1, T2, T3, T4, T5, T6, T7, T8 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.SequenceT8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t1, t2, t3, t4, t5, t6, t7, t8)
}
// SequenceSeqT8 converts 8 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func SequenceSeqT8[T1, T2, T3, T4, T5, T6, T7, T8 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.SequenceSeqT8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t1, t2, t3, t4, t5, t6, t7, t8)
}
// SequenceParT8 converts 8 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func SequenceParT8[T1, T2, T3, T4, T5, T6, T7, T8 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.SequenceParT8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t1, t2, t3, t4, t5, t6, t7, t8)
}
// SequenceTuple8 converts a [T.Tuple8] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func SequenceTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t T.Tuple8[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8]]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.SequenceTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t)
}
// SequenceSeqTuple8 converts a [T.Tuple8] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func SequenceSeqTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t T.Tuple8[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8]]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.SequenceSeqTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t)
}
// SequenceParTuple8 converts a [T.Tuple8] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func SequenceParTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t T.Tuple8[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8]]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.SequenceParTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t)
}
// TraverseTuple8 converts a [T.Tuple8] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func TraverseTuple8[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) func(T.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.TraverseTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](f1, f2, f3, f4, f5, f6, f7, f8)
}
// TraverseSeqTuple8 converts a [T.Tuple8] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func TraverseSeqTuple8[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) func(T.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.TraverseSeqTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](f1, f2, f3, f4, f5, f6, f7, f8)
}
// TraverseParTuple8 converts a [T.Tuple8] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func TraverseParTuple8[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) func(T.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.TraverseParTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](f1, f2, f3, f4, f5, f6, f7, f8)
}
// Eitherize9 converts a function with 9 parameters returning a tuple into a function with 9 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize9]
func Eitherize9[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8) ReaderIOEither[R] {
return G.Eitherize9[ReaderIOEither[R]](f)
}
// Uneitherize9 converts a function with 10 parameters returning a [ReaderIOEither[R]] into a function with 9 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize9[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8) ReaderIOEither[R], T0, T1, T2, T3, T4, T5, T6, T7, T8, R any](f F) func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error) {
return G.Uneitherize9[ReaderIOEither[R], func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error)](f)
}
// SequenceT9 converts 9 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func SequenceT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.SequenceT9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t1, t2, t3, t4, t5, t6, t7, t8, t9)
}
// SequenceSeqT9 converts 9 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func SequenceSeqT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.SequenceSeqT9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t1, t2, t3, t4, t5, t6, t7, t8, t9)
}
// SequenceParT9 converts 9 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func SequenceParT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.SequenceParT9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t1, t2, t3, t4, t5, t6, t7, t8, t9)
}
// SequenceTuple9 converts a [T.Tuple9] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func SequenceTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t T.Tuple9[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9]]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.SequenceTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t)
}
// SequenceSeqTuple9 converts a [T.Tuple9] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func SequenceSeqTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t T.Tuple9[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9]]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.SequenceSeqTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t)
}
// SequenceParTuple9 converts a [T.Tuple9] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func SequenceParTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t T.Tuple9[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9]]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.SequenceParTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t)
}
// TraverseTuple9 converts a [T.Tuple9] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func TraverseTuple9[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) func(T.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.TraverseTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](f1, f2, f3, f4, f5, f6, f7, f8, f9)
}
// TraverseSeqTuple9 converts a [T.Tuple9] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func TraverseSeqTuple9[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) func(T.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.TraverseSeqTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](f1, f2, f3, f4, f5, f6, f7, f8, f9)
}
// TraverseParTuple9 converts a [T.Tuple9] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func TraverseParTuple9[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) func(T.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.TraverseParTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](f1, f2, f3, f4, f5, f6, f7, f8, f9)
}
// Eitherize10 converts a function with 10 parameters returning a tuple into a function with 10 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize10]
func Eitherize10[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) ReaderIOEither[R] {
return G.Eitherize10[ReaderIOEither[R]](f)
}
// Uneitherize10 converts a function with 11 parameters returning a [ReaderIOEither[R]] into a function with 10 parameters returning a tuple.
// The first parameter is considered to be the [context.Context].
func Uneitherize10[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) ReaderIOEither[R], T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R any](f F) func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error) {
return G.Uneitherize10[ReaderIOEither[R], func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error)](f)
}
// SequenceT10 converts 10 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func SequenceT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9], t10 ReaderIOEither[T10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.SequenceT10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
}
// SequenceSeqT10 converts 10 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func SequenceSeqT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9], t10 ReaderIOEither[T10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.SequenceSeqT10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
}
// SequenceParT10 converts 10 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func SequenceParT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9], t10 ReaderIOEither[T10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.SequenceParT10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
}
// SequenceTuple10 converts a [T.Tuple10] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func SequenceTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t T.Tuple10[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9], ReaderIOEither[T10]]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.SequenceTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t)
}
// SequenceSeqTuple10 converts a [T.Tuple10] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func SequenceSeqTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t T.Tuple10[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9], ReaderIOEither[T10]]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.SequenceSeqTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t)
}
// SequenceParTuple10 converts a [T.Tuple10] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func SequenceParTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t T.Tuple10[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9], ReaderIOEither[T10]]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.SequenceParTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t)
}
// TraverseTuple10 converts a [T.Tuple10] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func TraverseTuple10[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], F10 ~func(A10) ReaderIOEither[T10], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) func(T.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.TraverseTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
}
// TraverseSeqTuple10 converts a [T.Tuple10] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func TraverseSeqTuple10[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], F10 ~func(A10) ReaderIOEither[T10], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) func(T.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.TraverseSeqTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
}
// TraverseParTuple10 converts a [T.Tuple10] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func TraverseParTuple10[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], F10 ~func(A10) ReaderIOEither[T10], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) func(T.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.TraverseParTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
}

View File

@@ -0,0 +1,92 @@
// 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 (
"context"
ET "github.com/IBM/fp-go/v2/either"
A "github.com/IBM/fp-go/v2/internal/apply"
C "github.com/IBM/fp-go/v2/internal/chain"
F "github.com/IBM/fp-go/v2/internal/functor"
)
// Bind creates an empty context of type [S] to be used with the [Bind] operation
func Do[GRS ~func(context.Context) GS, GS ~func() ET.Either[error, S], S any](
empty S,
) GRS {
return Of[GRS, GS, S](empty)
}
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
func Bind[GRS1 ~func(context.Context) GS1, GRS2 ~func(context.Context) GS2, GRT ~func(context.Context) GT, GS1 ~func() ET.Either[error, S1], GS2 ~func() ET.Either[error, S2], GT ~func() ET.Either[error, T], S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) GRT,
) func(GRS1) GRS2 {
return C.Bind(
Chain[GRS1, GRS2, GS1, GS2, S1, S2],
Map[GRT, GRS2, GT, GS2, T, S2],
setter,
f,
)
}
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
func Let[GRS1 ~func(context.Context) GS1, GRS2 ~func(context.Context) GS2, GS1 ~func() ET.Either[error, S1], GS2 ~func() ET.Either[error, S2], S1, S2, T any](
key func(T) func(S1) S2,
f func(S1) T,
) func(GRS1) GRS2 {
return F.Let(
Map[GRS1, GRS2, GS1, GS2, S1, S2],
key,
f,
)
}
// LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetTo[GRS1 ~func(context.Context) GS1, GRS2 ~func(context.Context) GS2, GS1 ~func() ET.Either[error, S1], GS2 ~func() ET.Either[error, S2], S1, S2, B any](
key func(B) func(S1) S2,
b B,
) func(GRS1) GRS2 {
return F.LetTo(
Map[GRS1, GRS2, GS1, GS2, S1, S2],
key,
b,
)
}
// BindTo initializes a new state [S1] from a value [T]
func BindTo[GRS1 ~func(context.Context) GS1, GRT ~func(context.Context) GT, GS1 ~func() ET.Either[error, S1], GT ~func() ET.Either[error, T], S1, T any](
setter func(T) S1,
) func(GRT) GRS1 {
return C.BindTo(
Map[GRT, GRS1, GT, GS1, T, S1],
setter,
)
}
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
func ApS[GRTS1 ~func(context.Context) GTS1, GRS1 ~func(context.Context) GS1, GRS2 ~func(context.Context) GS2, GRT ~func(context.Context) GT, GTS1 ~func() ET.Either[error, func(T) S2], GS1 ~func() ET.Either[error, S1], GS2 ~func() ET.Either[error, S2], GT ~func() ET.Either[error, T], S1, S2, T any](
setter func(T) func(S1) S2,
fa GRT,
) func(GRS1) GRS2 {
return A.ApS(
Ap[GRS2, GRTS1, GRT, GS2, GTS1, GT],
Map[GRS1, GRTS1, GS1, GTS1, S1, func(T) S2],
setter,
fa,
)
}

View File

@@ -0,0 +1,53 @@
// 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 (
"context"
E "github.com/IBM/fp-go/v2/either"
G "github.com/IBM/fp-go/v2/internal/bracket"
I "github.com/IBM/fp-go/v2/readerio/generic"
)
// Bracket makes sure that a resource is cleaned up in the event of an error. The release action is called regardless of
// whether the body action returns and error or not.
func Bracket[
GA ~func(context.Context) TA,
GB ~func(context.Context) TB,
GANY ~func(context.Context) TANY,
TA ~func() E.Either[error, A],
TB ~func() E.Either[error, B],
TANY ~func() E.Either[error, ANY],
A, B, ANY any](
acquire GA,
use func(A) GB,
release func(A, E.Either[error, B]) GANY,
) GB {
return G.Bracket[GA, GB, GANY, E.Either[error, B], A, B](
I.Of[GB, TB, context.Context, E.Either[error, B]],
MonadChain[GA, GB, TA, TB, A, B],
I.MonadChain[GB, GB, TB, TB, context.Context, E.Either[error, B], E.Either[error, B]],
MonadChain[GANY, GB, TANY, TB, ANY, B],
acquire,
use,
release,
)
}

View 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 (
"context"
CIOE "github.com/IBM/fp-go/v2/context/ioeither/generic"
E "github.com/IBM/fp-go/v2/either"
IOE "github.com/IBM/fp-go/v2/ioeither/generic"
)
// withContext wraps an existing ReaderIOEither and performs a context check for cancellation before delegating
func WithContext[GRA ~func(context.Context) GIOA, GIOA ~func() E.Either[error, A], A any](ma GRA) GRA {
return func(ctx context.Context) GIOA {
if err := context.Cause(ctx); err != nil {
return IOE.Left[GIOA](err)
}
return CIOE.WithContext(ctx, ma(ctx))
}
}

View File

@@ -0,0 +1,29 @@
// 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 (
"context"
E "github.com/IBM/fp-go/v2/either"
EQ "github.com/IBM/fp-go/v2/eq"
G "github.com/IBM/fp-go/v2/readerioeither/generic"
)
// Eq implements the equals predicate for values contained in the IOEither monad
func Eq[GRA ~func(context.Context) GIOA, GIOA ~func() E.Either[error, A], A any](eq EQ.Eq[E.Either[error, A]]) func(context.Context) EQ.Eq[GRA] {
return G.Eq[GRA](eq)
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More