1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-08-10 22:31:32 +02:00

fix: add ioeither

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
Dr. Carsten Leue
2023-07-14 17:30:58 +02:00
parent e350f70659
commit 5020437b6a
80 changed files with 5436 additions and 2110 deletions

View File

@@ -3,21 +3,21 @@ package array
import "github.com/ibm/fp-go/internal/array"
func Traverse[A, B, HKTB, HKTAB, HKTRB any](
_of func([]B) HKTRB,
_map func(HKTRB, func([]B) func(B) []B) HKTAB,
_ap func(HKTAB, HKTB) HKTRB,
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](_of, _map, _ap, f)
return array.Traverse[[]A](fof, fmap, fap, f)
}
func MonadTraverse[A, B, HKTB, HKTAB, HKTRB any](
_of func([]B) HKTRB,
_map func(HKTRB, func([]B) func(B) []B) HKTAB,
_ap func(HKTAB, HKTB) HKTRB,
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(_of, _map, _ap, ta, f)
return array.MonadTraverse(fof, fmap, fap, ta, f)
}

View File

@@ -13,8 +13,8 @@ func TestTraverse(t *testing.T) {
traverse := Traverse(
O.Of[ArrayType],
O.MonadMap[ArrayType, func(int) ArrayType],
O.MonadAp[ArrayType, int],
O.Map[ArrayType, func(int) ArrayType],
O.Ap[ArrayType, int],
func(n int) O.Option[int] {
if n%2 == 0 {

5
bytes/bytes.go Normal file
View File

@@ -0,0 +1,5 @@
package bytes
func ToString(a []byte) string {
return string(a)
}

19
bytes/monoid.go Normal file
View File

@@ -0,0 +1,19 @@
package bytes
import (
"bytes"
A "github.com/ibm/fp-go/array"
O "github.com/ibm/fp-go/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)
)

11
bytes/monoid_test.go Normal file
View File

@@ -0,0 +1,11 @@
package bytes
import (
"testing"
M "github.com/ibm/fp-go/monoid/testing"
)
func TestMonoid(t *testing.T) {
M.AssertLaws(t, Monoid)([][]byte{[]byte(""), []byte("a"), []byte("some value")})
}

127
cli/monad.go Normal file
View File

@@ -0,0 +1,127 @@
package cli
import (
"fmt"
"os"
"strings"
)
func tupleType(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("T%d", 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(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(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")
}
}

View File

@@ -3,201 +3,200 @@
// 2023-07-14 13:19:40.5850892 +0200 CEST m=+0.008180901
package either
// Eitherize0 converts a function with 0 parameters returning a tuple into a function with 0 parameters returning an Either
// The inverse function is [Uneitherize0]
func Eitherize0[F ~func() (R, error), R any](f F) func() Either[error, R] {
return func() Either[error, R] {
return TryCatchError(func() (R, error) {
return f()
})
}
return func() Either[error, R] {
return TryCatchError(func() (R, error) {
return f()
})
}
}
// Uneitherize0 converts a function with 0 parameters returning an Either into a function with 0 parameters returning a tuple
// The inverse function is [Eitherize0]
func Uneitherize0[F ~func() Either[error, R], R any](f F) func() (R, error) {
return func() (R, error) {
return UnwrapError(f())
}
return func() (R, error) {
return UnwrapError(f())
}
}
// Eitherize1 converts a function with 1 parameters returning a tuple into a function with 1 parameters returning an Either
// The inverse function is [Uneitherize1]
func Eitherize1[F ~func(T0) (R, error), T0, R any](f F) func(T0) Either[error, R] {
return func(t0 T0) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0)
})
}
return func(t0 T0) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0)
})
}
}
// Uneitherize1 converts a function with 1 parameters returning an Either into a function with 1 parameters returning a tuple
// The inverse function is [Eitherize1]
func Uneitherize1[F ~func(T0) Either[error, R], T0, R any](f F) func(T0) (R, error) {
return func(t0 T0) (R, error) {
return UnwrapError(f(t0))
}
return func(t0 T0) (R, error) {
return UnwrapError(f(t0))
}
}
// Eitherize2 converts a function with 2 parameters returning a tuple into a function with 2 parameters returning an Either
// The inverse function is [Uneitherize2]
func Eitherize2[F ~func(T0, T1) (R, error), T0, T1, R any](f F) func(T0, T1) Either[error, R] {
return func(t0 T0, t1 T1) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1)
})
}
return func(t0 T0, t1 T1) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1)
})
}
}
// Uneitherize2 converts a function with 2 parameters returning an Either into a function with 2 parameters returning a tuple
// The inverse function is [Eitherize2]
func Uneitherize2[F ~func(T0, T1) Either[error, R], T0, T1, R any](f F) func(T0, T1) (R, error) {
return func(t0 T0, t1 T1) (R, error) {
return UnwrapError(f(t0, t1))
}
return func(t0 T0, t1 T1) (R, error) {
return UnwrapError(f(t0, t1))
}
}
// Eitherize3 converts a function with 3 parameters returning a tuple into a function with 3 parameters returning an Either
// The inverse function is [Uneitherize3]
func Eitherize3[F ~func(T0, T1, T2) (R, error), T0, T1, T2, R any](f F) func(T0, T1, T2) Either[error, R] {
return func(t0 T0, t1 T1, t2 T2) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1, t2)
})
}
return func(t0 T0, t1 T1, t2 T2) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1, t2)
})
}
}
// Uneitherize3 converts a function with 3 parameters returning an Either into a function with 3 parameters returning a tuple
// The inverse function is [Eitherize3]
func Uneitherize3[F ~func(T0, T1, T2) Either[error, R], T0, T1, T2, R any](f F) func(T0, T1, T2) (R, error) {
return func(t0 T0, t1 T1, t2 T2) (R, error) {
return UnwrapError(f(t0, t1, t2))
}
return func(t0 T0, t1 T1, t2 T2) (R, error) {
return UnwrapError(f(t0, t1, t2))
}
}
// Eitherize4 converts a function with 4 parameters returning a tuple into a function with 4 parameters returning an Either
// The inverse function is [Uneitherize4]
func Eitherize4[F ~func(T0, T1, T2, T3) (R, error), T0, T1, T2, T3, R any](f F) func(T0, T1, T2, T3) Either[error, R] {
return func(t0 T0, t1 T1, t2 T2, t3 T3) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1, t2, t3)
})
}
return func(t0 T0, t1 T1, t2 T2, t3 T3) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1, t2, t3)
})
}
}
// Uneitherize4 converts a function with 4 parameters returning an Either into a function with 4 parameters returning a tuple
// The inverse function is [Eitherize4]
func Uneitherize4[F ~func(T0, T1, T2, T3) Either[error, R], T0, T1, T2, T3, R any](f F) func(T0, T1, T2, T3) (R, error) {
return func(t0 T0, t1 T1, t2 T2, t3 T3) (R, error) {
return UnwrapError(f(t0, t1, t2, t3))
}
return func(t0 T0, t1 T1, t2 T2, t3 T3) (R, error) {
return UnwrapError(f(t0, t1, t2, t3))
}
}
// Eitherize5 converts a function with 5 parameters returning a tuple into a function with 5 parameters returning an Either
// The inverse function is [Uneitherize5]
func Eitherize5[F ~func(T0, T1, T2, T3, T4) (R, error), T0, T1, T2, T3, T4, R any](f F) func(T0, T1, T2, T3, T4) Either[error, R] {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1, t2, t3, t4)
})
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1, t2, t3, t4)
})
}
}
// Uneitherize5 converts a function with 5 parameters returning an Either into a function with 5 parameters returning a tuple
// The inverse function is [Eitherize5]
func Uneitherize5[F ~func(T0, T1, T2, T3, T4) Either[error, R], T0, T1, T2, T3, T4, R any](f F) func(T0, T1, T2, T3, T4) (R, error) {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4) (R, error) {
return UnwrapError(f(t0, t1, t2, t3, t4))
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4) (R, error) {
return UnwrapError(f(t0, t1, t2, t3, t4))
}
}
// Eitherize6 converts a function with 6 parameters returning a tuple into a function with 6 parameters returning an Either
// The inverse function is [Uneitherize6]
func Eitherize6[F ~func(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) Either[error, R] {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1, t2, t3, t4, t5)
})
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1, t2, t3, t4, t5)
})
}
}
// Uneitherize6 converts a function with 6 parameters returning an Either into a function with 6 parameters returning a tuple
// The inverse function is [Eitherize6]
func Uneitherize6[F ~func(T0, T1, T2, T3, T4, T5) Either[error, R], T0, T1, T2, T3, T4, T5, R any](f F) func(T0, T1, T2, T3, T4, T5) (R, error) {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) (R, error) {
return UnwrapError(f(t0, t1, t2, t3, t4, t5))
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) (R, error) {
return UnwrapError(f(t0, t1, t2, t3, t4, t5))
}
}
// Eitherize7 converts a function with 7 parameters returning a tuple into a function with 7 parameters returning an Either
// The inverse function is [Uneitherize7]
func Eitherize7[F ~func(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) Either[error, R] {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1, t2, t3, t4, t5, t6)
})
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1, t2, t3, t4, t5, t6)
})
}
}
// Uneitherize7 converts a function with 7 parameters returning an Either into a function with 7 parameters returning a tuple
// The inverse function is [Eitherize7]
func Uneitherize7[F ~func(T0, T1, T2, T3, T4, T5, T6) Either[error, R], T0, T1, T2, T3, T4, T5, T6, R any](f F) func(T0, T1, T2, T3, T4, T5, T6) (R, error) {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) (R, error) {
return UnwrapError(f(t0, t1, t2, t3, t4, t5, t6))
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) (R, error) {
return UnwrapError(f(t0, t1, t2, t3, t4, t5, t6))
}
}
// Eitherize8 converts a function with 8 parameters returning a tuple into a function with 8 parameters returning an Either
// The inverse function is [Uneitherize8]
func Eitherize8[F ~func(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) Either[error, R] {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1, t2, t3, t4, t5, t6, t7)
})
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1, t2, t3, t4, t5, t6, t7)
})
}
}
// Uneitherize8 converts a function with 8 parameters returning an Either into a function with 8 parameters returning a tuple
// The inverse function is [Eitherize8]
func Uneitherize8[F ~func(T0, T1, T2, T3, T4, T5, T6, T7) Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7) (R, error) {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) (R, error) {
return UnwrapError(f(t0, t1, t2, t3, t4, t5, t6, t7))
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) (R, error) {
return UnwrapError(f(t0, t1, t2, t3, t4, t5, t6, t7))
}
}
// Eitherize9 converts a function with 9 parameters returning a tuple into a function with 9 parameters returning an Either
// The inverse function is [Uneitherize9]
func Eitherize9[F ~func(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) Either[error, R] {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1, t2, t3, t4, t5, t6, t7, t8)
})
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1, t2, t3, t4, t5, t6, t7, t8)
})
}
}
// Uneitherize9 converts a function with 9 parameters returning an Either into a function with 9 parameters returning a tuple
// The inverse function is [Eitherize9]
func Uneitherize9[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8) Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, T8, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error) {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) (R, error) {
return UnwrapError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8))
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) (R, error) {
return UnwrapError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8))
}
}
// Eitherize10 converts a function with 10 parameters returning a tuple into a function with 10 parameters returning an Either
// The inverse function is [Uneitherize10]
func Eitherize10[F ~func(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) Either[error, R] {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9)
})
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9)
})
}
}
// Uneitherize10 converts a function with 10 parameters returning an Either into a function with 10 parameters returning a tuple
// The inverse function is [Eitherize10]
func Uneitherize10[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) Either[error, R], 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) (R, error) {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) (R, error) {
return UnwrapError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9))
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) (R, error) {
return UnwrapError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9))
}
}

View File

@@ -9,8 +9,8 @@ import (
func TraverseRecordG[GA ~map[K]A, GB ~map[K]B, K comparable, E, A, B any](f func(A) Either[E, B]) func(GA) Either[E, GB] {
return RR.Traverse[GA](
Of[E, GB],
MonadMap[E, GB, func(B) GB],
MonadAp[GB, E, B],
Map[E, GB, func(B) GB],
Ap[GB, E, B],
f,
)
}

View File

@@ -2,449 +2,453 @@
// This file was generated by robots at
// 2023-07-14 13:19:42.9896471 +0200 CEST m=+0.009694501
package function
// Combinations for a total of 1 arguments
// Bind1of1 takes a function with 1 parameters and returns a new function with 1 parameters that will bind these parameters to the positions [1] of the original function.
// The return value of is a function with the remaining 0 parameters at positions [] of the original function.
func Bind1of1[F ~func(T1) R, T1, R any](f F) func(T1) func() R {
return func(t1 T1) func() R {
return func() R {
return f(t1)
}
}
return func(t1 T1) func() R {
return func() R {
return f(t1)
}
}
}
// Ignore1of1 takes a function with 0 parameters and returns a new function with 1 parameters that will ignore the values at positions [1] and pass the remaining 0 parameters to the original function
func Ignore1of1[T1 any, F ~func() R, R any](f F) func(T1) R {
return func(t1 T1) R {
return f()
}
return func(t1 T1) R {
return f()
}
}
// Combinations for a total of 2 arguments
// Bind1of2 takes a function with 2 parameters and returns a new function with 1 parameters that will bind these parameters to the positions [1] of the original function.
// The return value of is a function with the remaining 1 parameters at positions [2] of the original function.
func Bind1of2[F ~func(T1, T2) R, T1, T2, R any](f F) func(T1) func(T2) R {
return func(t1 T1) func(T2) R {
return func(t2 T2) R {
return f(t1, t2)
}
}
return func(t1 T1) func(T2) R {
return func(t2 T2) R {
return f(t1, t2)
}
}
}
// Ignore1of2 takes a function with 1 parameters and returns a new function with 2 parameters that will ignore the values at positions [1] and pass the remaining 1 parameters to the original function
func Ignore1of2[T1 any, F ~func(T2) R, T2, R any](f F) func(T1, T2) R {
return func(t1 T1, t2 T2) R {
return f(t2)
}
return func(t1 T1, t2 T2) R {
return f(t2)
}
}
// Bind2of2 takes a function with 2 parameters and returns a new function with 1 parameters that will bind these parameters to the positions [2] of the original function.
// The return value of is a function with the remaining 1 parameters at positions [1] of the original function.
func Bind2of2[F ~func(T1, T2) R, T1, T2, R any](f F) func(T2) func(T1) R {
return func(t2 T2) func(T1) R {
return func(t1 T1) R {
return f(t1, t2)
}
}
return func(t2 T2) func(T1) R {
return func(t1 T1) R {
return f(t1, t2)
}
}
}
// Ignore2of2 takes a function with 1 parameters and returns a new function with 2 parameters that will ignore the values at positions [2] and pass the remaining 1 parameters to the original function
func Ignore2of2[T2 any, F ~func(T1) R, T1, R any](f F) func(T1, T2) R {
return func(t1 T1, t2 T2) R {
return f(t1)
}
return func(t1 T1, t2 T2) R {
return f(t1)
}
}
// Bind12of2 takes a function with 2 parameters and returns a new function with 2 parameters that will bind these parameters to the positions [1, 2] of the original function.
// The return value of is a function with the remaining 0 parameters at positions [] of the original function.
func Bind12of2[F ~func(T1, T2) R, T1, T2, R any](f F) func(T1, T2) func() R {
return func(t1 T1, t2 T2) func() R {
return func() R {
return f(t1, t2)
}
}
return func(t1 T1, t2 T2) func() R {
return func() R {
return f(t1, t2)
}
}
}
// Ignore12of2 takes a function with 0 parameters and returns a new function with 2 parameters that will ignore the values at positions [1, 2] and pass the remaining 0 parameters to the original function
func Ignore12of2[T1, T2 any, F ~func() R, R any](f F) func(T1, T2) R {
return func(t1 T1, t2 T2) R {
return f()
}
return func(t1 T1, t2 T2) R {
return f()
}
}
// Combinations for a total of 3 arguments
// Bind1of3 takes a function with 3 parameters and returns a new function with 1 parameters that will bind these parameters to the positions [1] of the original function.
// The return value of is a function with the remaining 2 parameters at positions [2, 3] of the original function.
func Bind1of3[F ~func(T1, T2, T3) R, T1, T2, T3, R any](f F) func(T1) func(T2, T3) R {
return func(t1 T1) func(T2, T3) R {
return func(t2 T2, t3 T3) R {
return f(t1, t2, t3)
}
}
return func(t1 T1) func(T2, T3) R {
return func(t2 T2, t3 T3) R {
return f(t1, t2, t3)
}
}
}
// Ignore1of3 takes a function with 2 parameters and returns a new function with 3 parameters that will ignore the values at positions [1] and pass the remaining 2 parameters to the original function
func Ignore1of3[T1 any, F ~func(T2, T3) R, T2, T3, R any](f F) func(T1, T2, T3) R {
return func(t1 T1, t2 T2, t3 T3) R {
return f(t2, t3)
}
return func(t1 T1, t2 T2, t3 T3) R {
return f(t2, t3)
}
}
// Bind2of3 takes a function with 3 parameters and returns a new function with 1 parameters that will bind these parameters to the positions [2] of the original function.
// The return value of is a function with the remaining 2 parameters at positions [1, 3] of the original function.
func Bind2of3[F ~func(T1, T2, T3) R, T1, T2, T3, R any](f F) func(T2) func(T1, T3) R {
return func(t2 T2) func(T1, T3) R {
return func(t1 T1, t3 T3) R {
return f(t1, t2, t3)
}
}
return func(t2 T2) func(T1, T3) R {
return func(t1 T1, t3 T3) R {
return f(t1, t2, t3)
}
}
}
// Ignore2of3 takes a function with 2 parameters and returns a new function with 3 parameters that will ignore the values at positions [2] and pass the remaining 2 parameters to the original function
func Ignore2of3[T2 any, F ~func(T1, T3) R, T1, T3, R any](f F) func(T1, T2, T3) R {
return func(t1 T1, t2 T2, t3 T3) R {
return f(t1, t3)
}
return func(t1 T1, t2 T2, t3 T3) R {
return f(t1, t3)
}
}
// Bind3of3 takes a function with 3 parameters and returns a new function with 1 parameters that will bind these parameters to the positions [3] of the original function.
// The return value of is a function with the remaining 2 parameters at positions [1, 2] of the original function.
func Bind3of3[F ~func(T1, T2, T3) R, T1, T2, T3, R any](f F) func(T3) func(T1, T2) R {
return func(t3 T3) func(T1, T2) R {
return func(t1 T1, t2 T2) R {
return f(t1, t2, t3)
}
}
return func(t3 T3) func(T1, T2) R {
return func(t1 T1, t2 T2) R {
return f(t1, t2, t3)
}
}
}
// Ignore3of3 takes a function with 2 parameters and returns a new function with 3 parameters that will ignore the values at positions [3] and pass the remaining 2 parameters to the original function
func Ignore3of3[T3 any, F ~func(T1, T2) R, T1, T2, R any](f F) func(T1, T2, T3) R {
return func(t1 T1, t2 T2, t3 T3) R {
return f(t1, t2)
}
return func(t1 T1, t2 T2, t3 T3) R {
return f(t1, t2)
}
}
// Bind12of3 takes a function with 3 parameters and returns a new function with 2 parameters that will bind these parameters to the positions [1, 2] of the original function.
// The return value of is a function with the remaining 1 parameters at positions [3] of the original function.
func Bind12of3[F ~func(T1, T2, T3) R, T1, T2, T3, R any](f F) func(T1, T2) func(T3) R {
return func(t1 T1, t2 T2) func(T3) R {
return func(t3 T3) R {
return f(t1, t2, t3)
}
}
return func(t1 T1, t2 T2) func(T3) R {
return func(t3 T3) R {
return f(t1, t2, t3)
}
}
}
// Ignore12of3 takes a function with 1 parameters and returns a new function with 3 parameters that will ignore the values at positions [1, 2] and pass the remaining 1 parameters to the original function
func Ignore12of3[T1, T2 any, F ~func(T3) R, T3, R any](f F) func(T1, T2, T3) R {
return func(t1 T1, t2 T2, t3 T3) R {
return f(t3)
}
return func(t1 T1, t2 T2, t3 T3) R {
return f(t3)
}
}
// Bind13of3 takes a function with 3 parameters and returns a new function with 2 parameters that will bind these parameters to the positions [1, 3] of the original function.
// The return value of is a function with the remaining 1 parameters at positions [2] of the original function.
func Bind13of3[F ~func(T1, T2, T3) R, T1, T2, T3, R any](f F) func(T1, T3) func(T2) R {
return func(t1 T1, t3 T3) func(T2) R {
return func(t2 T2) R {
return f(t1, t2, t3)
}
}
return func(t1 T1, t3 T3) func(T2) R {
return func(t2 T2) R {
return f(t1, t2, t3)
}
}
}
// Ignore13of3 takes a function with 1 parameters and returns a new function with 3 parameters that will ignore the values at positions [1, 3] and pass the remaining 1 parameters to the original function
func Ignore13of3[T1, T3 any, F ~func(T2) R, T2, R any](f F) func(T1, T2, T3) R {
return func(t1 T1, t2 T2, t3 T3) R {
return f(t2)
}
return func(t1 T1, t2 T2, t3 T3) R {
return f(t2)
}
}
// Bind23of3 takes a function with 3 parameters and returns a new function with 2 parameters that will bind these parameters to the positions [2, 3] of the original function.
// The return value of is a function with the remaining 1 parameters at positions [1] of the original function.
func Bind23of3[F ~func(T1, T2, T3) R, T1, T2, T3, R any](f F) func(T2, T3) func(T1) R {
return func(t2 T2, t3 T3) func(T1) R {
return func(t1 T1) R {
return f(t1, t2, t3)
}
}
return func(t2 T2, t3 T3) func(T1) R {
return func(t1 T1) R {
return f(t1, t2, t3)
}
}
}
// Ignore23of3 takes a function with 1 parameters and returns a new function with 3 parameters that will ignore the values at positions [2, 3] and pass the remaining 1 parameters to the original function
func Ignore23of3[T2, T3 any, F ~func(T1) R, T1, R any](f F) func(T1, T2, T3) R {
return func(t1 T1, t2 T2, t3 T3) R {
return f(t1)
}
return func(t1 T1, t2 T2, t3 T3) R {
return f(t1)
}
}
// Bind123of3 takes a function with 3 parameters and returns a new function with 3 parameters that will bind these parameters to the positions [1, 2, 3] of the original function.
// The return value of is a function with the remaining 0 parameters at positions [] of the original function.
func Bind123of3[F ~func(T1, T2, T3) R, T1, T2, T3, R any](f F) func(T1, T2, T3) func() R {
return func(t1 T1, t2 T2, t3 T3) func() R {
return func() R {
return f(t1, t2, t3)
}
}
return func(t1 T1, t2 T2, t3 T3) func() R {
return func() R {
return f(t1, t2, t3)
}
}
}
// Ignore123of3 takes a function with 0 parameters and returns a new function with 3 parameters that will ignore the values at positions [1, 2, 3] and pass the remaining 0 parameters to the original function
func Ignore123of3[T1, T2, T3 any, F ~func() R, R any](f F) func(T1, T2, T3) R {
return func(t1 T1, t2 T2, t3 T3) R {
return f()
}
return func(t1 T1, t2 T2, t3 T3) R {
return f()
}
}
// Combinations for a total of 4 arguments
// Bind1of4 takes a function with 4 parameters and returns a new function with 1 parameters that will bind these parameters to the positions [1] of the original function.
// The return value of is a function with the remaining 3 parameters at positions [2, 3, 4] of the original function.
func Bind1of4[F ~func(T1, T2, T3, T4) R, T1, T2, T3, T4, R any](f F) func(T1) func(T2, T3, T4) R {
return func(t1 T1) func(T2, T3, T4) R {
return func(t2 T2, t3 T3, t4 T4) R {
return f(t1, t2, t3, t4)
}
}
return func(t1 T1) func(T2, T3, T4) R {
return func(t2 T2, t3 T3, t4 T4) R {
return f(t1, t2, t3, t4)
}
}
}
// Ignore1of4 takes a function with 3 parameters and returns a new function with 4 parameters that will ignore the values at positions [1] and pass the remaining 3 parameters to the original function
func Ignore1of4[T1 any, F ~func(T2, T3, T4) R, T2, T3, T4, R any](f F) func(T1, T2, T3, T4) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t2, t3, t4)
}
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t2, t3, t4)
}
}
// Bind2of4 takes a function with 4 parameters and returns a new function with 1 parameters that will bind these parameters to the positions [2] of the original function.
// The return value of is a function with the remaining 3 parameters at positions [1, 3, 4] of the original function.
func Bind2of4[F ~func(T1, T2, T3, T4) R, T1, T2, T3, T4, R any](f F) func(T2) func(T1, T3, T4) R {
return func(t2 T2) func(T1, T3, T4) R {
return func(t1 T1, t3 T3, t4 T4) R {
return f(t1, t2, t3, t4)
}
}
return func(t2 T2) func(T1, T3, T4) R {
return func(t1 T1, t3 T3, t4 T4) R {
return f(t1, t2, t3, t4)
}
}
}
// Ignore2of4 takes a function with 3 parameters and returns a new function with 4 parameters that will ignore the values at positions [2] and pass the remaining 3 parameters to the original function
func Ignore2of4[T2 any, F ~func(T1, T3, T4) R, T1, T3, T4, R any](f F) func(T1, T2, T3, T4) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t1, t3, t4)
}
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t1, t3, t4)
}
}
// Bind3of4 takes a function with 4 parameters and returns a new function with 1 parameters that will bind these parameters to the positions [3] of the original function.
// The return value of is a function with the remaining 3 parameters at positions [1, 2, 4] of the original function.
func Bind3of4[F ~func(T1, T2, T3, T4) R, T1, T2, T3, T4, R any](f F) func(T3) func(T1, T2, T4) R {
return func(t3 T3) func(T1, T2, T4) R {
return func(t1 T1, t2 T2, t4 T4) R {
return f(t1, t2, t3, t4)
}
}
return func(t3 T3) func(T1, T2, T4) R {
return func(t1 T1, t2 T2, t4 T4) R {
return f(t1, t2, t3, t4)
}
}
}
// Ignore3of4 takes a function with 3 parameters and returns a new function with 4 parameters that will ignore the values at positions [3] and pass the remaining 3 parameters to the original function
func Ignore3of4[T3 any, F ~func(T1, T2, T4) R, T1, T2, T4, R any](f F) func(T1, T2, T3, T4) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t1, t2, t4)
}
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t1, t2, t4)
}
}
// Bind4of4 takes a function with 4 parameters and returns a new function with 1 parameters that will bind these parameters to the positions [4] of the original function.
// The return value of is a function with the remaining 3 parameters at positions [1, 2, 3] of the original function.
func Bind4of4[F ~func(T1, T2, T3, T4) R, T1, T2, T3, T4, R any](f F) func(T4) func(T1, T2, T3) R {
return func(t4 T4) func(T1, T2, T3) R {
return func(t1 T1, t2 T2, t3 T3) R {
return f(t1, t2, t3, t4)
}
}
return func(t4 T4) func(T1, T2, T3) R {
return func(t1 T1, t2 T2, t3 T3) R {
return f(t1, t2, t3, t4)
}
}
}
// Ignore4of4 takes a function with 3 parameters and returns a new function with 4 parameters that will ignore the values at positions [4] and pass the remaining 3 parameters to the original function
func Ignore4of4[T4 any, F ~func(T1, T2, T3) R, T1, T2, T3, R any](f F) func(T1, T2, T3, T4) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t1, t2, t3)
}
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t1, t2, t3)
}
}
// Bind12of4 takes a function with 4 parameters and returns a new function with 2 parameters that will bind these parameters to the positions [1, 2] of the original function.
// The return value of is a function with the remaining 2 parameters at positions [3, 4] of the original function.
func Bind12of4[F ~func(T1, T2, T3, T4) R, T1, T2, T3, T4, R any](f F) func(T1, T2) func(T3, T4) R {
return func(t1 T1, t2 T2) func(T3, T4) R {
return func(t3 T3, t4 T4) R {
return f(t1, t2, t3, t4)
}
}
return func(t1 T1, t2 T2) func(T3, T4) R {
return func(t3 T3, t4 T4) R {
return f(t1, t2, t3, t4)
}
}
}
// Ignore12of4 takes a function with 2 parameters and returns a new function with 4 parameters that will ignore the values at positions [1, 2] and pass the remaining 2 parameters to the original function
func Ignore12of4[T1, T2 any, F ~func(T3, T4) R, T3, T4, R any](f F) func(T1, T2, T3, T4) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t3, t4)
}
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t3, t4)
}
}
// Bind13of4 takes a function with 4 parameters and returns a new function with 2 parameters that will bind these parameters to the positions [1, 3] of the original function.
// The return value of is a function with the remaining 2 parameters at positions [2, 4] of the original function.
func Bind13of4[F ~func(T1, T2, T3, T4) R, T1, T2, T3, T4, R any](f F) func(T1, T3) func(T2, T4) R {
return func(t1 T1, t3 T3) func(T2, T4) R {
return func(t2 T2, t4 T4) R {
return f(t1, t2, t3, t4)
}
}
return func(t1 T1, t3 T3) func(T2, T4) R {
return func(t2 T2, t4 T4) R {
return f(t1, t2, t3, t4)
}
}
}
// Ignore13of4 takes a function with 2 parameters and returns a new function with 4 parameters that will ignore the values at positions [1, 3] and pass the remaining 2 parameters to the original function
func Ignore13of4[T1, T3 any, F ~func(T2, T4) R, T2, T4, R any](f F) func(T1, T2, T3, T4) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t2, t4)
}
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t2, t4)
}
}
// Bind14of4 takes a function with 4 parameters and returns a new function with 2 parameters that will bind these parameters to the positions [1, 4] of the original function.
// The return value of is a function with the remaining 2 parameters at positions [2, 3] of the original function.
func Bind14of4[F ~func(T1, T2, T3, T4) R, T1, T2, T3, T4, R any](f F) func(T1, T4) func(T2, T3) R {
return func(t1 T1, t4 T4) func(T2, T3) R {
return func(t2 T2, t3 T3) R {
return f(t1, t2, t3, t4)
}
}
return func(t1 T1, t4 T4) func(T2, T3) R {
return func(t2 T2, t3 T3) R {
return f(t1, t2, t3, t4)
}
}
}
// Ignore14of4 takes a function with 2 parameters and returns a new function with 4 parameters that will ignore the values at positions [1, 4] and pass the remaining 2 parameters to the original function
func Ignore14of4[T1, T4 any, F ~func(T2, T3) R, T2, T3, R any](f F) func(T1, T2, T3, T4) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t2, t3)
}
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t2, t3)
}
}
// Bind23of4 takes a function with 4 parameters and returns a new function with 2 parameters that will bind these parameters to the positions [2, 3] of the original function.
// The return value of is a function with the remaining 2 parameters at positions [1, 4] of the original function.
func Bind23of4[F ~func(T1, T2, T3, T4) R, T1, T2, T3, T4, R any](f F) func(T2, T3) func(T1, T4) R {
return func(t2 T2, t3 T3) func(T1, T4) R {
return func(t1 T1, t4 T4) R {
return f(t1, t2, t3, t4)
}
}
return func(t2 T2, t3 T3) func(T1, T4) R {
return func(t1 T1, t4 T4) R {
return f(t1, t2, t3, t4)
}
}
}
// Ignore23of4 takes a function with 2 parameters and returns a new function with 4 parameters that will ignore the values at positions [2, 3] and pass the remaining 2 parameters to the original function
func Ignore23of4[T2, T3 any, F ~func(T1, T4) R, T1, T4, R any](f F) func(T1, T2, T3, T4) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t1, t4)
}
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t1, t4)
}
}
// Bind24of4 takes a function with 4 parameters and returns a new function with 2 parameters that will bind these parameters to the positions [2, 4] of the original function.
// The return value of is a function with the remaining 2 parameters at positions [1, 3] of the original function.
func Bind24of4[F ~func(T1, T2, T3, T4) R, T1, T2, T3, T4, R any](f F) func(T2, T4) func(T1, T3) R {
return func(t2 T2, t4 T4) func(T1, T3) R {
return func(t1 T1, t3 T3) R {
return f(t1, t2, t3, t4)
}
}
return func(t2 T2, t4 T4) func(T1, T3) R {
return func(t1 T1, t3 T3) R {
return f(t1, t2, t3, t4)
}
}
}
// Ignore24of4 takes a function with 2 parameters and returns a new function with 4 parameters that will ignore the values at positions [2, 4] and pass the remaining 2 parameters to the original function
func Ignore24of4[T2, T4 any, F ~func(T1, T3) R, T1, T3, R any](f F) func(T1, T2, T3, T4) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t1, t3)
}
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t1, t3)
}
}
// Bind34of4 takes a function with 4 parameters and returns a new function with 2 parameters that will bind these parameters to the positions [3, 4] of the original function.
// The return value of is a function with the remaining 2 parameters at positions [1, 2] of the original function.
func Bind34of4[F ~func(T1, T2, T3, T4) R, T1, T2, T3, T4, R any](f F) func(T3, T4) func(T1, T2) R {
return func(t3 T3, t4 T4) func(T1, T2) R {
return func(t1 T1, t2 T2) R {
return f(t1, t2, t3, t4)
}
}
return func(t3 T3, t4 T4) func(T1, T2) R {
return func(t1 T1, t2 T2) R {
return f(t1, t2, t3, t4)
}
}
}
// Ignore34of4 takes a function with 2 parameters and returns a new function with 4 parameters that will ignore the values at positions [3, 4] and pass the remaining 2 parameters to the original function
func Ignore34of4[T3, T4 any, F ~func(T1, T2) R, T1, T2, R any](f F) func(T1, T2, T3, T4) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t1, t2)
}
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t1, t2)
}
}
// Bind123of4 takes a function with 4 parameters and returns a new function with 3 parameters that will bind these parameters to the positions [1, 2, 3] of the original function.
// The return value of is a function with the remaining 1 parameters at positions [4] of the original function.
func Bind123of4[F ~func(T1, T2, T3, T4) R, T1, T2, T3, T4, R any](f F) func(T1, T2, T3) func(T4) R {
return func(t1 T1, t2 T2, t3 T3) func(T4) R {
return func(t4 T4) R {
return f(t1, t2, t3, t4)
}
}
return func(t1 T1, t2 T2, t3 T3) func(T4) R {
return func(t4 T4) R {
return f(t1, t2, t3, t4)
}
}
}
// Ignore123of4 takes a function with 1 parameters and returns a new function with 4 parameters that will ignore the values at positions [1, 2, 3] and pass the remaining 1 parameters to the original function
func Ignore123of4[T1, T2, T3 any, F ~func(T4) R, T4, R any](f F) func(T1, T2, T3, T4) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t4)
}
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t4)
}
}
// Bind124of4 takes a function with 4 parameters and returns a new function with 3 parameters that will bind these parameters to the positions [1, 2, 4] of the original function.
// The return value of is a function with the remaining 1 parameters at positions [3] of the original function.
func Bind124of4[F ~func(T1, T2, T3, T4) R, T1, T2, T3, T4, R any](f F) func(T1, T2, T4) func(T3) R {
return func(t1 T1, t2 T2, t4 T4) func(T3) R {
return func(t3 T3) R {
return f(t1, t2, t3, t4)
}
}
return func(t1 T1, t2 T2, t4 T4) func(T3) R {
return func(t3 T3) R {
return f(t1, t2, t3, t4)
}
}
}
// Ignore124of4 takes a function with 1 parameters and returns a new function with 4 parameters that will ignore the values at positions [1, 2, 4] and pass the remaining 1 parameters to the original function
func Ignore124of4[T1, T2, T4 any, F ~func(T3) R, T3, R any](f F) func(T1, T2, T3, T4) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t3)
}
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t3)
}
}
// Bind134of4 takes a function with 4 parameters and returns a new function with 3 parameters that will bind these parameters to the positions [1, 3, 4] of the original function.
// The return value of is a function with the remaining 1 parameters at positions [2] of the original function.
func Bind134of4[F ~func(T1, T2, T3, T4) R, T1, T2, T3, T4, R any](f F) func(T1, T3, T4) func(T2) R {
return func(t1 T1, t3 T3, t4 T4) func(T2) R {
return func(t2 T2) R {
return f(t1, t2, t3, t4)
}
}
return func(t1 T1, t3 T3, t4 T4) func(T2) R {
return func(t2 T2) R {
return f(t1, t2, t3, t4)
}
}
}
// Ignore134of4 takes a function with 1 parameters and returns a new function with 4 parameters that will ignore the values at positions [1, 3, 4] and pass the remaining 1 parameters to the original function
func Ignore134of4[T1, T3, T4 any, F ~func(T2) R, T2, R any](f F) func(T1, T2, T3, T4) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t2)
}
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t2)
}
}
// Bind234of4 takes a function with 4 parameters and returns a new function with 3 parameters that will bind these parameters to the positions [2, 3, 4] of the original function.
// The return value of is a function with the remaining 1 parameters at positions [1] of the original function.
func Bind234of4[F ~func(T1, T2, T3, T4) R, T1, T2, T3, T4, R any](f F) func(T2, T3, T4) func(T1) R {
return func(t2 T2, t3 T3, t4 T4) func(T1) R {
return func(t1 T1) R {
return f(t1, t2, t3, t4)
}
}
return func(t2 T2, t3 T3, t4 T4) func(T1) R {
return func(t1 T1) R {
return f(t1, t2, t3, t4)
}
}
}
// Ignore234of4 takes a function with 1 parameters and returns a new function with 4 parameters that will ignore the values at positions [2, 3, 4] and pass the remaining 1 parameters to the original function
func Ignore234of4[T2, T3, T4 any, F ~func(T1) R, T1, R any](f F) func(T1, T2, T3, T4) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t1)
}
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(t1)
}
}
// Bind1234of4 takes a function with 4 parameters and returns a new function with 4 parameters that will bind these parameters to the positions [1, 2, 3, 4] of the original function.
// The return value of is a function with the remaining 0 parameters at positions [] of the original function.
func Bind1234of4[F ~func(T1, T2, T3, T4) R, T1, T2, T3, T4, R any](f F) func(T1, T2, T3, T4) func() R {
return func(t1 T1, t2 T2, t3 T3, t4 T4) func() R {
return func() R {
return f(t1, t2, t3, t4)
}
}
return func(t1 T1, t2 T2, t3 T3, t4 T4) func() R {
return func() R {
return f(t1, t2, t3, t4)
}
}
}
// Ignore1234of4 takes a function with 0 parameters and returns a new function with 4 parameters that will ignore the values at positions [1, 2, 3, 4] and pass the remaining 0 parameters to the original function
func Ignore1234of4[T1, T2, T3, T4 any, F ~func() R, R any](f F) func(T1, T2, T3, T4) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f()
}
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f()
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,6 @@
// 2023-07-14 13:19:44.2638147 +0200 CEST m=+0.009515201
package apply
import (
F "github.com/ibm/fp-go/function"
T "github.com/ibm/fp-go/tuple"
@@ -11,535 +10,535 @@ import (
// tupleConstructor1 returns a curried version of [T.MakeTuple1]
func tupleConstructor1[T1 any]() func(T1) T.Tuple1[T1] {
return F.Curry1(T.MakeTuple1[T1])
return F.Curry1(T.MakeTuple1[T1])
}
// SequenceT1 is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.
// The function takes 1 higher higher kinded types and returns a higher kinded type of a [Tuple1] with the resolved values.
func SequenceT1[
MAP ~func(func(T1) T.Tuple1[T1]) func(HKT_T1) HKT_TUPLE1,
T1,
HKT_T1, // HKT[T1]
HKT_TUPLE1 any, // HKT[Tuple1[T1]]
MAP ~func(func(T1) T.Tuple1[T1]) func(HKT_T1) HKT_TUPLE1,
T1,
HKT_T1, // HKT[T1]
HKT_TUPLE1 any, // HKT[Tuple1[T1]]
](
fmap MAP,
t1 HKT_T1,
fmap MAP,
t1 HKT_T1,
) HKT_TUPLE1 {
return F.Pipe1(
t1,
fmap(tupleConstructor1[T1]()),
)
return F.Pipe1(
t1,
fmap(tupleConstructor1[T1]()),
)
}
// tupleConstructor2 returns a curried version of [T.MakeTuple2]
func tupleConstructor2[T1, T2 any]() func(T1) func(T2) T.Tuple2[T1, T2] {
return F.Curry2(T.MakeTuple2[T1, T2])
return F.Curry2(T.MakeTuple2[T1, T2])
}
// SequenceT2 is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.
// The function takes 2 higher higher kinded types and returns a higher kinded type of a [Tuple2] with the resolved values.
func SequenceT2[
MAP ~func(func(T1) func(T2) T.Tuple2[T1, T2]) func(HKT_T1) HKT_F_T2,
AP1 ~func(HKT_T2) func(HKT_F_T2) HKT_TUPLE2,
T1,
T2,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_F_T2, // HKT[func(T2) T.Tuple2[T1, T2]]
HKT_TUPLE2 any, // HKT[Tuple2[T1, T2]]
MAP ~func(func(T1) func(T2) T.Tuple2[T1, T2]) func(HKT_T1) HKT_F_T2,
AP1 ~func(HKT_T2) func(HKT_F_T2) HKT_TUPLE2,
T1,
T2,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_F_T2, // HKT[func(T2) T.Tuple2[T1, T2]]
HKT_TUPLE2 any, // HKT[Tuple2[T1, T2]]
](
fmap MAP,
fap1 AP1,
t1 HKT_T1,
t2 HKT_T2,
fmap MAP,
fap1 AP1,
t1 HKT_T1,
t2 HKT_T2,
) HKT_TUPLE2 {
return F.Pipe2(
t1,
fmap(tupleConstructor2[T1, T2]()),
fap1(t2),
)
return F.Pipe2(
t1,
fmap(tupleConstructor2[T1, T2]()),
fap1(t2),
)
}
// tupleConstructor3 returns a curried version of [T.MakeTuple3]
func tupleConstructor3[T1, T2, T3 any]() func(T1) func(T2) func(T3) T.Tuple3[T1, T2, T3] {
return F.Curry3(T.MakeTuple3[T1, T2, T3])
return F.Curry3(T.MakeTuple3[T1, T2, T3])
}
// SequenceT3 is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.
// The function takes 3 higher higher kinded types and returns a higher kinded type of a [Tuple3] with the resolved values.
func SequenceT3[
MAP ~func(func(T1) func(T2) func(T3) T.Tuple3[T1, T2, T3]) func(HKT_T1) HKT_F_T2_T3,
AP1 ~func(HKT_T2) func(HKT_F_T2_T3) HKT_F_T3,
AP2 ~func(HKT_T3) func(HKT_F_T3) HKT_TUPLE3,
T1,
T2,
T3,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_T3, // HKT[T3]
HKT_F_T2_T3, // HKT[func(T2) func(T3) T.Tuple3[T1, T2, T3]]
HKT_F_T3, // HKT[func(T3) T.Tuple3[T1, T2, T3]]
HKT_TUPLE3 any, // HKT[Tuple3[T1, T2, T3]]
MAP ~func(func(T1) func(T2) func(T3) T.Tuple3[T1, T2, T3]) func(HKT_T1) HKT_F_T2_T3,
AP1 ~func(HKT_T2) func(HKT_F_T2_T3) HKT_F_T3,
AP2 ~func(HKT_T3) func(HKT_F_T3) HKT_TUPLE3,
T1,
T2,
T3,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_T3, // HKT[T3]
HKT_F_T2_T3, // HKT[func(T2) func(T3) T.Tuple3[T1, T2, T3]]
HKT_F_T3, // HKT[func(T3) T.Tuple3[T1, T2, T3]]
HKT_TUPLE3 any, // HKT[Tuple3[T1, T2, T3]]
](
fmap MAP,
fap1 AP1,
fap2 AP2,
t1 HKT_T1,
t2 HKT_T2,
t3 HKT_T3,
fmap MAP,
fap1 AP1,
fap2 AP2,
t1 HKT_T1,
t2 HKT_T2,
t3 HKT_T3,
) HKT_TUPLE3 {
return F.Pipe3(
t1,
fmap(tupleConstructor3[T1, T2, T3]()),
fap1(t2),
fap2(t3),
)
return F.Pipe3(
t1,
fmap(tupleConstructor3[T1, T2, T3]()),
fap1(t2),
fap2(t3),
)
}
// tupleConstructor4 returns a curried version of [T.MakeTuple4]
func tupleConstructor4[T1, T2, T3, T4 any]() func(T1) func(T2) func(T3) func(T4) T.Tuple4[T1, T2, T3, T4] {
return F.Curry4(T.MakeTuple4[T1, T2, T3, T4])
return F.Curry4(T.MakeTuple4[T1, T2, T3, T4])
}
// SequenceT4 is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.
// The function takes 4 higher higher kinded types and returns a higher kinded type of a [Tuple4] with the resolved values.
func SequenceT4[
MAP ~func(func(T1) func(T2) func(T3) func(T4) T.Tuple4[T1, T2, T3, T4]) func(HKT_T1) HKT_F_T2_T3_T4,
AP1 ~func(HKT_T2) func(HKT_F_T2_T3_T4) HKT_F_T3_T4,
AP2 ~func(HKT_T3) func(HKT_F_T3_T4) HKT_F_T4,
AP3 ~func(HKT_T4) func(HKT_F_T4) HKT_TUPLE4,
T1,
T2,
T3,
T4,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_T3, // HKT[T3]
HKT_T4, // HKT[T4]
HKT_F_T2_T3_T4, // HKT[func(T2) func(T3) func(T4) T.Tuple4[T1, T2, T3, T4]]
HKT_F_T3_T4, // HKT[func(T3) func(T4) T.Tuple4[T1, T2, T3, T4]]
HKT_F_T4, // HKT[func(T4) T.Tuple4[T1, T2, T3, T4]]
HKT_TUPLE4 any, // HKT[Tuple4[T1, T2, T3, T4]]
MAP ~func(func(T1) func(T2) func(T3) func(T4) T.Tuple4[T1, T2, T3, T4]) func(HKT_T1) HKT_F_T2_T3_T4,
AP1 ~func(HKT_T2) func(HKT_F_T2_T3_T4) HKT_F_T3_T4,
AP2 ~func(HKT_T3) func(HKT_F_T3_T4) HKT_F_T4,
AP3 ~func(HKT_T4) func(HKT_F_T4) HKT_TUPLE4,
T1,
T2,
T3,
T4,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_T3, // HKT[T3]
HKT_T4, // HKT[T4]
HKT_F_T2_T3_T4, // HKT[func(T2) func(T3) func(T4) T.Tuple4[T1, T2, T3, T4]]
HKT_F_T3_T4, // HKT[func(T3) func(T4) T.Tuple4[T1, T2, T3, T4]]
HKT_F_T4, // HKT[func(T4) T.Tuple4[T1, T2, T3, T4]]
HKT_TUPLE4 any, // HKT[Tuple4[T1, T2, T3, T4]]
](
fmap MAP,
fap1 AP1,
fap2 AP2,
fap3 AP3,
t1 HKT_T1,
t2 HKT_T2,
t3 HKT_T3,
t4 HKT_T4,
fmap MAP,
fap1 AP1,
fap2 AP2,
fap3 AP3,
t1 HKT_T1,
t2 HKT_T2,
t3 HKT_T3,
t4 HKT_T4,
) HKT_TUPLE4 {
return F.Pipe4(
t1,
fmap(tupleConstructor4[T1, T2, T3, T4]()),
fap1(t2),
fap2(t3),
fap3(t4),
)
return F.Pipe4(
t1,
fmap(tupleConstructor4[T1, T2, T3, T4]()),
fap1(t2),
fap2(t3),
fap3(t4),
)
}
// tupleConstructor5 returns a curried version of [T.MakeTuple5]
func tupleConstructor5[T1, T2, T3, T4, T5 any]() func(T1) func(T2) func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5] {
return F.Curry5(T.MakeTuple5[T1, T2, T3, T4, T5])
return F.Curry5(T.MakeTuple5[T1, T2, T3, T4, T5])
}
// SequenceT5 is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.
// The function takes 5 higher higher kinded types and returns a higher kinded type of a [Tuple5] with the resolved values.
func SequenceT5[
MAP ~func(func(T1) func(T2) func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5]) func(HKT_T1) HKT_F_T2_T3_T4_T5,
AP1 ~func(HKT_T2) func(HKT_F_T2_T3_T4_T5) HKT_F_T3_T4_T5,
AP2 ~func(HKT_T3) func(HKT_F_T3_T4_T5) HKT_F_T4_T5,
AP3 ~func(HKT_T4) func(HKT_F_T4_T5) HKT_F_T5,
AP4 ~func(HKT_T5) func(HKT_F_T5) HKT_TUPLE5,
T1,
T2,
T3,
T4,
T5,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_T3, // HKT[T3]
HKT_T4, // HKT[T4]
HKT_T5, // HKT[T5]
HKT_F_T2_T3_T4_T5, // HKT[func(T2) func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5]]
HKT_F_T3_T4_T5, // HKT[func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5]]
HKT_F_T4_T5, // HKT[func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5]]
HKT_F_T5, // HKT[func(T5) T.Tuple5[T1, T2, T3, T4, T5]]
HKT_TUPLE5 any, // HKT[Tuple5[T1, T2, T3, T4, T5]]
MAP ~func(func(T1) func(T2) func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5]) func(HKT_T1) HKT_F_T2_T3_T4_T5,
AP1 ~func(HKT_T2) func(HKT_F_T2_T3_T4_T5) HKT_F_T3_T4_T5,
AP2 ~func(HKT_T3) func(HKT_F_T3_T4_T5) HKT_F_T4_T5,
AP3 ~func(HKT_T4) func(HKT_F_T4_T5) HKT_F_T5,
AP4 ~func(HKT_T5) func(HKT_F_T5) HKT_TUPLE5,
T1,
T2,
T3,
T4,
T5,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_T3, // HKT[T3]
HKT_T4, // HKT[T4]
HKT_T5, // HKT[T5]
HKT_F_T2_T3_T4_T5, // HKT[func(T2) func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5]]
HKT_F_T3_T4_T5, // HKT[func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5]]
HKT_F_T4_T5, // HKT[func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5]]
HKT_F_T5, // HKT[func(T5) T.Tuple5[T1, T2, T3, T4, T5]]
HKT_TUPLE5 any, // HKT[Tuple5[T1, T2, T3, T4, T5]]
](
fmap MAP,
fap1 AP1,
fap2 AP2,
fap3 AP3,
fap4 AP4,
t1 HKT_T1,
t2 HKT_T2,
t3 HKT_T3,
t4 HKT_T4,
t5 HKT_T5,
fmap MAP,
fap1 AP1,
fap2 AP2,
fap3 AP3,
fap4 AP4,
t1 HKT_T1,
t2 HKT_T2,
t3 HKT_T3,
t4 HKT_T4,
t5 HKT_T5,
) HKT_TUPLE5 {
return F.Pipe5(
t1,
fmap(tupleConstructor5[T1, T2, T3, T4, T5]()),
fap1(t2),
fap2(t3),
fap3(t4),
fap4(t5),
)
return F.Pipe5(
t1,
fmap(tupleConstructor5[T1, T2, T3, T4, T5]()),
fap1(t2),
fap2(t3),
fap3(t4),
fap4(t5),
)
}
// tupleConstructor6 returns a curried version of [T.MakeTuple6]
func tupleConstructor6[T1, T2, T3, T4, T5, T6 any]() func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6] {
return F.Curry6(T.MakeTuple6[T1, T2, T3, T4, T5, T6])
return F.Curry6(T.MakeTuple6[T1, T2, T3, T4, T5, T6])
}
// SequenceT6 is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.
// The function takes 6 higher higher kinded types and returns a higher kinded type of a [Tuple6] with the resolved values.
func SequenceT6[
MAP ~func(func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6]) func(HKT_T1) HKT_F_T2_T3_T4_T5_T6,
AP1 ~func(HKT_T2) func(HKT_F_T2_T3_T4_T5_T6) HKT_F_T3_T4_T5_T6,
AP2 ~func(HKT_T3) func(HKT_F_T3_T4_T5_T6) HKT_F_T4_T5_T6,
AP3 ~func(HKT_T4) func(HKT_F_T4_T5_T6) HKT_F_T5_T6,
AP4 ~func(HKT_T5) func(HKT_F_T5_T6) HKT_F_T6,
AP5 ~func(HKT_T6) func(HKT_F_T6) HKT_TUPLE6,
T1,
T2,
T3,
T4,
T5,
T6,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_T3, // HKT[T3]
HKT_T4, // HKT[T4]
HKT_T5, // HKT[T5]
HKT_T6, // HKT[T6]
HKT_F_T2_T3_T4_T5_T6, // HKT[func(T2) func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6]]
HKT_F_T3_T4_T5_T6, // HKT[func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6]]
HKT_F_T4_T5_T6, // HKT[func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6]]
HKT_F_T5_T6, // HKT[func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6]]
HKT_F_T6, // HKT[func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6]]
HKT_TUPLE6 any, // HKT[Tuple6[T1, T2, T3, T4, T5, T6]]
MAP ~func(func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6]) func(HKT_T1) HKT_F_T2_T3_T4_T5_T6,
AP1 ~func(HKT_T2) func(HKT_F_T2_T3_T4_T5_T6) HKT_F_T3_T4_T5_T6,
AP2 ~func(HKT_T3) func(HKT_F_T3_T4_T5_T6) HKT_F_T4_T5_T6,
AP3 ~func(HKT_T4) func(HKT_F_T4_T5_T6) HKT_F_T5_T6,
AP4 ~func(HKT_T5) func(HKT_F_T5_T6) HKT_F_T6,
AP5 ~func(HKT_T6) func(HKT_F_T6) HKT_TUPLE6,
T1,
T2,
T3,
T4,
T5,
T6,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_T3, // HKT[T3]
HKT_T4, // HKT[T4]
HKT_T5, // HKT[T5]
HKT_T6, // HKT[T6]
HKT_F_T2_T3_T4_T5_T6, // HKT[func(T2) func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6]]
HKT_F_T3_T4_T5_T6, // HKT[func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6]]
HKT_F_T4_T5_T6, // HKT[func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6]]
HKT_F_T5_T6, // HKT[func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6]]
HKT_F_T6, // HKT[func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6]]
HKT_TUPLE6 any, // HKT[Tuple6[T1, T2, T3, T4, T5, T6]]
](
fmap MAP,
fap1 AP1,
fap2 AP2,
fap3 AP3,
fap4 AP4,
fap5 AP5,
t1 HKT_T1,
t2 HKT_T2,
t3 HKT_T3,
t4 HKT_T4,
t5 HKT_T5,
t6 HKT_T6,
fmap MAP,
fap1 AP1,
fap2 AP2,
fap3 AP3,
fap4 AP4,
fap5 AP5,
t1 HKT_T1,
t2 HKT_T2,
t3 HKT_T3,
t4 HKT_T4,
t5 HKT_T5,
t6 HKT_T6,
) HKT_TUPLE6 {
return F.Pipe6(
t1,
fmap(tupleConstructor6[T1, T2, T3, T4, T5, T6]()),
fap1(t2),
fap2(t3),
fap3(t4),
fap4(t5),
fap5(t6),
)
return F.Pipe6(
t1,
fmap(tupleConstructor6[T1, T2, T3, T4, T5, T6]()),
fap1(t2),
fap2(t3),
fap3(t4),
fap4(t5),
fap5(t6),
)
}
// tupleConstructor7 returns a curried version of [T.MakeTuple7]
func tupleConstructor7[T1, T2, T3, T4, T5, T6, T7 any]() func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7] {
return F.Curry7(T.MakeTuple7[T1, T2, T3, T4, T5, T6, T7])
return F.Curry7(T.MakeTuple7[T1, T2, T3, T4, T5, T6, T7])
}
// SequenceT7 is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.
// The function takes 7 higher higher kinded types and returns a higher kinded type of a [Tuple7] with the resolved values.
func SequenceT7[
MAP ~func(func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7]) func(HKT_T1) HKT_F_T2_T3_T4_T5_T6_T7,
AP1 ~func(HKT_T2) func(HKT_F_T2_T3_T4_T5_T6_T7) HKT_F_T3_T4_T5_T6_T7,
AP2 ~func(HKT_T3) func(HKT_F_T3_T4_T5_T6_T7) HKT_F_T4_T5_T6_T7,
AP3 ~func(HKT_T4) func(HKT_F_T4_T5_T6_T7) HKT_F_T5_T6_T7,
AP4 ~func(HKT_T5) func(HKT_F_T5_T6_T7) HKT_F_T6_T7,
AP5 ~func(HKT_T6) func(HKT_F_T6_T7) HKT_F_T7,
AP6 ~func(HKT_T7) func(HKT_F_T7) HKT_TUPLE7,
T1,
T2,
T3,
T4,
T5,
T6,
T7,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_T3, // HKT[T3]
HKT_T4, // HKT[T4]
HKT_T5, // HKT[T5]
HKT_T6, // HKT[T6]
HKT_T7, // HKT[T7]
HKT_F_T2_T3_T4_T5_T6_T7, // HKT[func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
HKT_F_T3_T4_T5_T6_T7, // HKT[func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
HKT_F_T4_T5_T6_T7, // HKT[func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
HKT_F_T5_T6_T7, // HKT[func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
HKT_F_T6_T7, // HKT[func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
HKT_F_T7, // HKT[func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
HKT_TUPLE7 any, // HKT[Tuple7[T1, T2, T3, T4, T5, T6, T7]]
MAP ~func(func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7]) func(HKT_T1) HKT_F_T2_T3_T4_T5_T6_T7,
AP1 ~func(HKT_T2) func(HKT_F_T2_T3_T4_T5_T6_T7) HKT_F_T3_T4_T5_T6_T7,
AP2 ~func(HKT_T3) func(HKT_F_T3_T4_T5_T6_T7) HKT_F_T4_T5_T6_T7,
AP3 ~func(HKT_T4) func(HKT_F_T4_T5_T6_T7) HKT_F_T5_T6_T7,
AP4 ~func(HKT_T5) func(HKT_F_T5_T6_T7) HKT_F_T6_T7,
AP5 ~func(HKT_T6) func(HKT_F_T6_T7) HKT_F_T7,
AP6 ~func(HKT_T7) func(HKT_F_T7) HKT_TUPLE7,
T1,
T2,
T3,
T4,
T5,
T6,
T7,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_T3, // HKT[T3]
HKT_T4, // HKT[T4]
HKT_T5, // HKT[T5]
HKT_T6, // HKT[T6]
HKT_T7, // HKT[T7]
HKT_F_T2_T3_T4_T5_T6_T7, // HKT[func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
HKT_F_T3_T4_T5_T6_T7, // HKT[func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
HKT_F_T4_T5_T6_T7, // HKT[func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
HKT_F_T5_T6_T7, // HKT[func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
HKT_F_T6_T7, // HKT[func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
HKT_F_T7, // HKT[func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
HKT_TUPLE7 any, // HKT[Tuple7[T1, T2, T3, T4, T5, T6, T7]]
](
fmap MAP,
fap1 AP1,
fap2 AP2,
fap3 AP3,
fap4 AP4,
fap5 AP5,
fap6 AP6,
t1 HKT_T1,
t2 HKT_T2,
t3 HKT_T3,
t4 HKT_T4,
t5 HKT_T5,
t6 HKT_T6,
t7 HKT_T7,
fmap MAP,
fap1 AP1,
fap2 AP2,
fap3 AP3,
fap4 AP4,
fap5 AP5,
fap6 AP6,
t1 HKT_T1,
t2 HKT_T2,
t3 HKT_T3,
t4 HKT_T4,
t5 HKT_T5,
t6 HKT_T6,
t7 HKT_T7,
) HKT_TUPLE7 {
return F.Pipe7(
t1,
fmap(tupleConstructor7[T1, T2, T3, T4, T5, T6, T7]()),
fap1(t2),
fap2(t3),
fap3(t4),
fap4(t5),
fap5(t6),
fap6(t7),
)
return F.Pipe7(
t1,
fmap(tupleConstructor7[T1, T2, T3, T4, T5, T6, T7]()),
fap1(t2),
fap2(t3),
fap3(t4),
fap4(t5),
fap5(t6),
fap6(t7),
)
}
// tupleConstructor8 returns a curried version of [T.MakeTuple8]
func tupleConstructor8[T1, T2, T3, T4, T5, T6, T7, T8 any]() func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8] {
return F.Curry8(T.MakeTuple8[T1, T2, T3, T4, T5, T6, T7, T8])
return F.Curry8(T.MakeTuple8[T1, T2, T3, T4, T5, T6, T7, T8])
}
// SequenceT8 is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.
// The function takes 8 higher higher kinded types and returns a higher kinded type of a [Tuple8] with the resolved values.
func SequenceT8[
MAP ~func(func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]) func(HKT_T1) HKT_F_T2_T3_T4_T5_T6_T7_T8,
AP1 ~func(HKT_T2) func(HKT_F_T2_T3_T4_T5_T6_T7_T8) HKT_F_T3_T4_T5_T6_T7_T8,
AP2 ~func(HKT_T3) func(HKT_F_T3_T4_T5_T6_T7_T8) HKT_F_T4_T5_T6_T7_T8,
AP3 ~func(HKT_T4) func(HKT_F_T4_T5_T6_T7_T8) HKT_F_T5_T6_T7_T8,
AP4 ~func(HKT_T5) func(HKT_F_T5_T6_T7_T8) HKT_F_T6_T7_T8,
AP5 ~func(HKT_T6) func(HKT_F_T6_T7_T8) HKT_F_T7_T8,
AP6 ~func(HKT_T7) func(HKT_F_T7_T8) HKT_F_T8,
AP7 ~func(HKT_T8) func(HKT_F_T8) HKT_TUPLE8,
T1,
T2,
T3,
T4,
T5,
T6,
T7,
T8,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_T3, // HKT[T3]
HKT_T4, // HKT[T4]
HKT_T5, // HKT[T5]
HKT_T6, // HKT[T6]
HKT_T7, // HKT[T7]
HKT_T8, // HKT[T8]
HKT_F_T2_T3_T4_T5_T6_T7_T8, // HKT[func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
HKT_F_T3_T4_T5_T6_T7_T8, // HKT[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
HKT_F_T4_T5_T6_T7_T8, // HKT[func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
HKT_F_T5_T6_T7_T8, // HKT[func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
HKT_F_T6_T7_T8, // HKT[func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
HKT_F_T7_T8, // HKT[func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
HKT_F_T8, // HKT[func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
HKT_TUPLE8 any, // HKT[Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
MAP ~func(func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]) func(HKT_T1) HKT_F_T2_T3_T4_T5_T6_T7_T8,
AP1 ~func(HKT_T2) func(HKT_F_T2_T3_T4_T5_T6_T7_T8) HKT_F_T3_T4_T5_T6_T7_T8,
AP2 ~func(HKT_T3) func(HKT_F_T3_T4_T5_T6_T7_T8) HKT_F_T4_T5_T6_T7_T8,
AP3 ~func(HKT_T4) func(HKT_F_T4_T5_T6_T7_T8) HKT_F_T5_T6_T7_T8,
AP4 ~func(HKT_T5) func(HKT_F_T5_T6_T7_T8) HKT_F_T6_T7_T8,
AP5 ~func(HKT_T6) func(HKT_F_T6_T7_T8) HKT_F_T7_T8,
AP6 ~func(HKT_T7) func(HKT_F_T7_T8) HKT_F_T8,
AP7 ~func(HKT_T8) func(HKT_F_T8) HKT_TUPLE8,
T1,
T2,
T3,
T4,
T5,
T6,
T7,
T8,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_T3, // HKT[T3]
HKT_T4, // HKT[T4]
HKT_T5, // HKT[T5]
HKT_T6, // HKT[T6]
HKT_T7, // HKT[T7]
HKT_T8, // HKT[T8]
HKT_F_T2_T3_T4_T5_T6_T7_T8, // HKT[func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
HKT_F_T3_T4_T5_T6_T7_T8, // HKT[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
HKT_F_T4_T5_T6_T7_T8, // HKT[func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
HKT_F_T5_T6_T7_T8, // HKT[func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
HKT_F_T6_T7_T8, // HKT[func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
HKT_F_T7_T8, // HKT[func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
HKT_F_T8, // HKT[func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
HKT_TUPLE8 any, // HKT[Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
](
fmap MAP,
fap1 AP1,
fap2 AP2,
fap3 AP3,
fap4 AP4,
fap5 AP5,
fap6 AP6,
fap7 AP7,
t1 HKT_T1,
t2 HKT_T2,
t3 HKT_T3,
t4 HKT_T4,
t5 HKT_T5,
t6 HKT_T6,
t7 HKT_T7,
t8 HKT_T8,
fmap MAP,
fap1 AP1,
fap2 AP2,
fap3 AP3,
fap4 AP4,
fap5 AP5,
fap6 AP6,
fap7 AP7,
t1 HKT_T1,
t2 HKT_T2,
t3 HKT_T3,
t4 HKT_T4,
t5 HKT_T5,
t6 HKT_T6,
t7 HKT_T7,
t8 HKT_T8,
) HKT_TUPLE8 {
return F.Pipe8(
t1,
fmap(tupleConstructor8[T1, T2, T3, T4, T5, T6, T7, T8]()),
fap1(t2),
fap2(t3),
fap3(t4),
fap4(t5),
fap5(t6),
fap6(t7),
fap7(t8),
)
return F.Pipe8(
t1,
fmap(tupleConstructor8[T1, T2, T3, T4, T5, T6, T7, T8]()),
fap1(t2),
fap2(t3),
fap3(t4),
fap4(t5),
fap5(t6),
fap6(t7),
fap7(t8),
)
}
// tupleConstructor9 returns a curried version of [T.MakeTuple9]
func tupleConstructor9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any]() func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9] {
return F.Curry9(T.MakeTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9])
return F.Curry9(T.MakeTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9])
}
// SequenceT9 is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.
// The function takes 9 higher higher kinded types and returns a higher kinded type of a [Tuple9] with the resolved values.
func SequenceT9[
MAP ~func(func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]) func(HKT_T1) HKT_F_T2_T3_T4_T5_T6_T7_T8_T9,
AP1 ~func(HKT_T2) func(HKT_F_T2_T3_T4_T5_T6_T7_T8_T9) HKT_F_T3_T4_T5_T6_T7_T8_T9,
AP2 ~func(HKT_T3) func(HKT_F_T3_T4_T5_T6_T7_T8_T9) HKT_F_T4_T5_T6_T7_T8_T9,
AP3 ~func(HKT_T4) func(HKT_F_T4_T5_T6_T7_T8_T9) HKT_F_T5_T6_T7_T8_T9,
AP4 ~func(HKT_T5) func(HKT_F_T5_T6_T7_T8_T9) HKT_F_T6_T7_T8_T9,
AP5 ~func(HKT_T6) func(HKT_F_T6_T7_T8_T9) HKT_F_T7_T8_T9,
AP6 ~func(HKT_T7) func(HKT_F_T7_T8_T9) HKT_F_T8_T9,
AP7 ~func(HKT_T8) func(HKT_F_T8_T9) HKT_F_T9,
AP8 ~func(HKT_T9) func(HKT_F_T9) HKT_TUPLE9,
T1,
T2,
T3,
T4,
T5,
T6,
T7,
T8,
T9,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_T3, // HKT[T3]
HKT_T4, // HKT[T4]
HKT_T5, // HKT[T5]
HKT_T6, // HKT[T6]
HKT_T7, // HKT[T7]
HKT_T8, // HKT[T8]
HKT_T9, // HKT[T9]
HKT_F_T2_T3_T4_T5_T6_T7_T8_T9, // HKT[func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
HKT_F_T3_T4_T5_T6_T7_T8_T9, // HKT[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
HKT_F_T4_T5_T6_T7_T8_T9, // HKT[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
HKT_F_T5_T6_T7_T8_T9, // HKT[func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
HKT_F_T6_T7_T8_T9, // HKT[func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
HKT_F_T7_T8_T9, // HKT[func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
HKT_F_T8_T9, // HKT[func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
HKT_F_T9, // HKT[func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
HKT_TUPLE9 any, // HKT[Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
MAP ~func(func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]) func(HKT_T1) HKT_F_T2_T3_T4_T5_T6_T7_T8_T9,
AP1 ~func(HKT_T2) func(HKT_F_T2_T3_T4_T5_T6_T7_T8_T9) HKT_F_T3_T4_T5_T6_T7_T8_T9,
AP2 ~func(HKT_T3) func(HKT_F_T3_T4_T5_T6_T7_T8_T9) HKT_F_T4_T5_T6_T7_T8_T9,
AP3 ~func(HKT_T4) func(HKT_F_T4_T5_T6_T7_T8_T9) HKT_F_T5_T6_T7_T8_T9,
AP4 ~func(HKT_T5) func(HKT_F_T5_T6_T7_T8_T9) HKT_F_T6_T7_T8_T9,
AP5 ~func(HKT_T6) func(HKT_F_T6_T7_T8_T9) HKT_F_T7_T8_T9,
AP6 ~func(HKT_T7) func(HKT_F_T7_T8_T9) HKT_F_T8_T9,
AP7 ~func(HKT_T8) func(HKT_F_T8_T9) HKT_F_T9,
AP8 ~func(HKT_T9) func(HKT_F_T9) HKT_TUPLE9,
T1,
T2,
T3,
T4,
T5,
T6,
T7,
T8,
T9,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_T3, // HKT[T3]
HKT_T4, // HKT[T4]
HKT_T5, // HKT[T5]
HKT_T6, // HKT[T6]
HKT_T7, // HKT[T7]
HKT_T8, // HKT[T8]
HKT_T9, // HKT[T9]
HKT_F_T2_T3_T4_T5_T6_T7_T8_T9, // HKT[func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
HKT_F_T3_T4_T5_T6_T7_T8_T9, // HKT[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
HKT_F_T4_T5_T6_T7_T8_T9, // HKT[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
HKT_F_T5_T6_T7_T8_T9, // HKT[func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
HKT_F_T6_T7_T8_T9, // HKT[func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
HKT_F_T7_T8_T9, // HKT[func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
HKT_F_T8_T9, // HKT[func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
HKT_F_T9, // HKT[func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
HKT_TUPLE9 any, // HKT[Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
](
fmap MAP,
fap1 AP1,
fap2 AP2,
fap3 AP3,
fap4 AP4,
fap5 AP5,
fap6 AP6,
fap7 AP7,
fap8 AP8,
t1 HKT_T1,
t2 HKT_T2,
t3 HKT_T3,
t4 HKT_T4,
t5 HKT_T5,
t6 HKT_T6,
t7 HKT_T7,
t8 HKT_T8,
t9 HKT_T9,
fmap MAP,
fap1 AP1,
fap2 AP2,
fap3 AP3,
fap4 AP4,
fap5 AP5,
fap6 AP6,
fap7 AP7,
fap8 AP8,
t1 HKT_T1,
t2 HKT_T2,
t3 HKT_T3,
t4 HKT_T4,
t5 HKT_T5,
t6 HKT_T6,
t7 HKT_T7,
t8 HKT_T8,
t9 HKT_T9,
) HKT_TUPLE9 {
return F.Pipe9(
t1,
fmap(tupleConstructor9[T1, T2, T3, T4, T5, T6, T7, T8, T9]()),
fap1(t2),
fap2(t3),
fap3(t4),
fap4(t5),
fap5(t6),
fap6(t7),
fap7(t8),
fap8(t9),
)
return F.Pipe9(
t1,
fmap(tupleConstructor9[T1, T2, T3, T4, T5, T6, T7, T8, T9]()),
fap1(t2),
fap2(t3),
fap3(t4),
fap4(t5),
fap5(t6),
fap6(t7),
fap7(t8),
fap8(t9),
)
}
// tupleConstructor10 returns a curried version of [T.MakeTuple10]
func tupleConstructor10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any]() func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10] {
return F.Curry10(T.MakeTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10])
return F.Curry10(T.MakeTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10])
}
// SequenceT10 is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.
// The function takes 10 higher higher kinded types and returns a higher kinded type of a [Tuple10] with the resolved values.
func SequenceT10[
MAP ~func(func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]) func(HKT_T1) HKT_F_T2_T3_T4_T5_T6_T7_T8_T9_T10,
AP1 ~func(HKT_T2) func(HKT_F_T2_T3_T4_T5_T6_T7_T8_T9_T10) HKT_F_T3_T4_T5_T6_T7_T8_T9_T10,
AP2 ~func(HKT_T3) func(HKT_F_T3_T4_T5_T6_T7_T8_T9_T10) HKT_F_T4_T5_T6_T7_T8_T9_T10,
AP3 ~func(HKT_T4) func(HKT_F_T4_T5_T6_T7_T8_T9_T10) HKT_F_T5_T6_T7_T8_T9_T10,
AP4 ~func(HKT_T5) func(HKT_F_T5_T6_T7_T8_T9_T10) HKT_F_T6_T7_T8_T9_T10,
AP5 ~func(HKT_T6) func(HKT_F_T6_T7_T8_T9_T10) HKT_F_T7_T8_T9_T10,
AP6 ~func(HKT_T7) func(HKT_F_T7_T8_T9_T10) HKT_F_T8_T9_T10,
AP7 ~func(HKT_T8) func(HKT_F_T8_T9_T10) HKT_F_T9_T10,
AP8 ~func(HKT_T9) func(HKT_F_T9_T10) HKT_F_T10,
AP9 ~func(HKT_T10) func(HKT_F_T10) HKT_TUPLE10,
T1,
T2,
T3,
T4,
T5,
T6,
T7,
T8,
T9,
T10,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_T3, // HKT[T3]
HKT_T4, // HKT[T4]
HKT_T5, // HKT[T5]
HKT_T6, // HKT[T6]
HKT_T7, // HKT[T7]
HKT_T8, // HKT[T8]
HKT_T9, // HKT[T9]
HKT_T10, // HKT[T10]
HKT_F_T2_T3_T4_T5_T6_T7_T8_T9_T10, // HKT[func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_F_T3_T4_T5_T6_T7_T8_T9_T10, // HKT[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_F_T4_T5_T6_T7_T8_T9_T10, // HKT[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_F_T5_T6_T7_T8_T9_T10, // HKT[func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_F_T6_T7_T8_T9_T10, // HKT[func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_F_T7_T8_T9_T10, // HKT[func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_F_T8_T9_T10, // HKT[func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_F_T9_T10, // HKT[func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_F_T10, // HKT[func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_TUPLE10 any, // HKT[Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
MAP ~func(func(T1) func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]) func(HKT_T1) HKT_F_T2_T3_T4_T5_T6_T7_T8_T9_T10,
AP1 ~func(HKT_T2) func(HKT_F_T2_T3_T4_T5_T6_T7_T8_T9_T10) HKT_F_T3_T4_T5_T6_T7_T8_T9_T10,
AP2 ~func(HKT_T3) func(HKT_F_T3_T4_T5_T6_T7_T8_T9_T10) HKT_F_T4_T5_T6_T7_T8_T9_T10,
AP3 ~func(HKT_T4) func(HKT_F_T4_T5_T6_T7_T8_T9_T10) HKT_F_T5_T6_T7_T8_T9_T10,
AP4 ~func(HKT_T5) func(HKT_F_T5_T6_T7_T8_T9_T10) HKT_F_T6_T7_T8_T9_T10,
AP5 ~func(HKT_T6) func(HKT_F_T6_T7_T8_T9_T10) HKT_F_T7_T8_T9_T10,
AP6 ~func(HKT_T7) func(HKT_F_T7_T8_T9_T10) HKT_F_T8_T9_T10,
AP7 ~func(HKT_T8) func(HKT_F_T8_T9_T10) HKT_F_T9_T10,
AP8 ~func(HKT_T9) func(HKT_F_T9_T10) HKT_F_T10,
AP9 ~func(HKT_T10) func(HKT_F_T10) HKT_TUPLE10,
T1,
T2,
T3,
T4,
T5,
T6,
T7,
T8,
T9,
T10,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_T3, // HKT[T3]
HKT_T4, // HKT[T4]
HKT_T5, // HKT[T5]
HKT_T6, // HKT[T6]
HKT_T7, // HKT[T7]
HKT_T8, // HKT[T8]
HKT_T9, // HKT[T9]
HKT_T10, // HKT[T10]
HKT_F_T2_T3_T4_T5_T6_T7_T8_T9_T10, // HKT[func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_F_T3_T4_T5_T6_T7_T8_T9_T10, // HKT[func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_F_T4_T5_T6_T7_T8_T9_T10, // HKT[func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_F_T5_T6_T7_T8_T9_T10, // HKT[func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_F_T6_T7_T8_T9_T10, // HKT[func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_F_T7_T8_T9_T10, // HKT[func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_F_T8_T9_T10, // HKT[func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_F_T9_T10, // HKT[func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_F_T10, // HKT[func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
HKT_TUPLE10 any, // HKT[Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
](
fmap MAP,
fap1 AP1,
fap2 AP2,
fap3 AP3,
fap4 AP4,
fap5 AP5,
fap6 AP6,
fap7 AP7,
fap8 AP8,
fap9 AP9,
t1 HKT_T1,
t2 HKT_T2,
t3 HKT_T3,
t4 HKT_T4,
t5 HKT_T5,
t6 HKT_T6,
t7 HKT_T7,
t8 HKT_T8,
t9 HKT_T9,
t10 HKT_T10,
fmap MAP,
fap1 AP1,
fap2 AP2,
fap3 AP3,
fap4 AP4,
fap5 AP5,
fap6 AP6,
fap7 AP7,
fap8 AP8,
fap9 AP9,
t1 HKT_T1,
t2 HKT_T2,
t3 HKT_T3,
t4 HKT_T4,
t5 HKT_T5,
t6 HKT_T6,
t7 HKT_T7,
t8 HKT_T8,
t9 HKT_T9,
t10 HKT_T10,
) HKT_TUPLE10 {
return F.Pipe10(
t1,
fmap(tupleConstructor10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]()),
fap1(t2),
fap2(t3),
fap3(t4),
fap4(t5),
fap5(t6),
fap6(t7),
fap7(t8),
fap8(t9),
fap9(t10),
)
return F.Pipe10(
t1,
fmap(tupleConstructor10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]()),
fap1(t2),
fap2(t3),
fap3(t4),
fap4(t5),
fap5(t6),
fap6(t7),
fap7(t8),
fap8(t9),
fap9(t10),
)
}

View File

@@ -13,31 +13,31 @@ HKTB = HKT<B>
HKTAB = HKT<func(A)B>
*/
func MonadTraverse[GA ~[]A, GB ~[]B, A, B, HKTB, HKTAB, HKTRB any](
_of func(GB) HKTRB,
_map func(HKTRB, func(GB) func(B) GB) HKTAB,
_ap func(HKTAB, HKTB) HKTRB,
fof func(GB) HKTRB,
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
fap func(HKTB) func(HKTAB) HKTRB,
ta GA,
f func(A) HKTB) HKTRB {
return MonadTraverseReduce(_of, _map, _ap, ta, f, Append[GB, B], Empty[GB]())
return MonadTraverseReduce(fof, fmap, fap, ta, f, Append[GB, B], Empty[GB]())
}
func Traverse[GA ~[]A, GB ~[]B, A, B, HKTB, HKTAB, HKTRB any](
_of func(GB) HKTRB,
_map func(HKTRB, func(GB) func(B) GB) HKTAB,
_ap func(HKTAB, HKTB) HKTRB,
fof func(GB) HKTRB,
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
fap func(HKTB) func(HKTAB) HKTRB,
f func(A) HKTB) func(GA) HKTRB {
return func(ma GA) HKTRB {
return MonadTraverse(_of, _map, _ap, ma, f)
return MonadTraverse(fof, fmap, fap, ma, f)
}
}
func MonadTraverseReduce[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any](
_of func(GB) HKTRB,
_map func(HKTRB, func(GB) func(B) GB) HKTAB,
_ap func(HKTAB, HKTB) HKTRB,
fof func(GB) HKTRB,
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
fap func(HKTB) func(HKTAB) HKTRB,
ta GA,
@@ -45,26 +45,27 @@ func MonadTraverseReduce[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any](
reduce func(GB, B) GB,
initial GB,
) HKTRB {
mmap := F.Bind2nd(_map, F.Curry2(reduce))
mmap := fmap(F.Curry2(reduce))
return Reduce(ta, func(r HKTRB, a A) HKTRB {
return _ap(
mmap(r),
transform(a),
return F.Pipe2(
r,
mmap,
fap(transform(a)),
)
}, _of(initial))
}, fof(initial))
}
func TraverseReduce[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any](
_of func(GB) HKTRB,
_map func(HKTRB, func(GB) func(B) GB) HKTAB,
_ap func(HKTAB, HKTB) HKTRB,
fof func(GB) HKTRB,
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
fap func(HKTB) func(HKTAB) HKTRB,
transform func(A) HKTB,
reduce func(GB, B) GB,
initial GB,
) func(GA) HKTRB {
return func(ta GA) HKTRB {
return MonadTraverseReduce(_of, _map, _ap, ta, transform, reduce, initial)
return MonadTraverseReduce(fof, fmap, fap, ta, transform, reduce, initial)
}
}

108
internal/eithert/either.go Normal file
View File

@@ -0,0 +1,108 @@
package eithert
import (
ET "github.com/ibm/fp-go/either"
F "github.com/ibm/fp-go/function"
"github.com/ibm/fp-go/internal/apply"
FC "github.com/ibm/fp-go/internal/functor"
)
// HKTFA = HKT<F, Either<E, A>>
// HKTFB = HKT<F, Either<E, B>>
func MonadMap[E, A, B, HKTFA, HKTFB any](fmap func(HKTFA, func(ET.Either[E, A]) ET.Either[E, B]) HKTFB, fa HKTFA, f func(A) B) HKTFB {
// HKTGA = Either[E, A]
// HKTGB = Either[E, B]
return FC.MonadMap(fmap, ET.MonadMap[E, A, B], fa, f)
}
// HKTFA = HKT<F, Either<E, A>>
// HKTFB = HKT<F, Either<E, B>>
func MonadBiMap[E1, E2, A, B, HKTFA, HKTFB any](fmap func(HKTFA, func(ET.Either[E1, A]) ET.Either[E2, B]) HKTFB, fa HKTFA, f func(E1) E2, g func(A) B) HKTFB {
// HKTGA = Either[E, A]
// HKTGB = Either[E, B]
return fmap(fa, ET.BiMap(f, g))
}
// HKTFA = HKT<F, Either<E, A>>
// HKTFB = HKT<F, Either<E, B>>
func BiMap[E1, E2, A, B, HKTFA, HKTFB any](fmap func(HKTFA, func(ET.Either[E1, A]) ET.Either[E2, B]) HKTFB, f func(E1) E2, g func(A) B) func(HKTFA) HKTFB {
// HKTGA = Either[E, A]
// HKTGB = Either[E, B]
return F.Bind2nd(fmap, ET.BiMap(f, g))
}
// HKTFA = HKT<F, Either<E, A>>
// HKTFB = HKT<F, Either<E, B>>
func MonadChain[E, A, B, HKTFA, HKTFB any](
fchain func(HKTFA, func(ET.Either[E, A]) HKTFB) HKTFB,
fof func(ET.Either[E, B]) HKTFB,
ma HKTFA,
f func(A) HKTFB) HKTFB {
// dispatch to the even more generic implementation
return fchain(ma, ET.Fold(F.Flow2(ET.Left[B, E], fof), f))
}
// func(fa func(R) T.Task[ET.Either[E, func(A) B]], f func(ET.Either[E, func(A) B]) func(ET.Either[E, A]) ET.Either[E, B]) GEFAB
// HKTFA = HKT[Either[E, A]]
// HKTFB = HKT[Either[E, B]]
// HKTFAB = HKT[Either[E, func(A)B]]
func MonadAp[E, A, B, HKTFAB, HKTFGAB, HKTFA, HKTFB any](
fap func(HKTFGAB, HKTFA) HKTFB,
fmap func(HKTFAB, func(ET.Either[E, func(A) B]) func(ET.Either[E, A]) ET.Either[E, B]) HKTFGAB,
fab HKTFAB,
fa HKTFA) HKTFB {
// HKTGA = ET.Either[E, A]
// HKTGB = ET.Either[E, B]
// HKTGAB = ET.Either[E, func(a A) B]
return apply.MonadAp(fap, fmap, ET.MonadAp[B, E, A], fab, fa)
}
func Right[E, A, HKTA any](fof func(ET.Either[E, A]) HKTA, a A) HKTA {
return F.Pipe2(a, ET.Right[E, A], fof)
}
func Left[E, A, HKTA any](fof func(ET.Either[E, A]) HKTA, e E) HKTA {
return F.Pipe2(e, ET.Left[A, E], fof)
}
// HKTA = HKT[A]
// HKTEA = HKT[Either[E, A]]
func RightF[E, A, HKTA, HKTEA any](fmap func(HKTA, func(A) ET.Either[E, A]) HKTEA, fa HKTA) HKTEA {
return fmap(fa, ET.Right[E, A])
}
// HKTE = HKT[E]
// HKTEA = HKT[Either[E, A]]
func LeftF[E, A, HKTE, HKTEA any](fmap func(HKTE, func(E) ET.Either[E, A]) HKTEA, fe HKTE) HKTEA {
return fmap(fe, ET.Left[A, E])
}
func FoldE[E, A, HKTEA, HKTB any](mchain func(HKTEA, func(ET.Either[E, A]) HKTB) HKTB, ma HKTEA, onLeft func(E) HKTB, onRight func(A) HKTB) HKTB {
return mchain(ma, ET.Fold(onLeft, onRight))
}
func MatchE[E, A, HKTEA, HKTB any](mchain func(HKTEA, func(ET.Either[E, A]) HKTB) HKTB, onLeft func(E) HKTB, onRight func(A) HKTB) func(HKTEA) HKTB {
return F.Bind2nd(mchain, ET.Fold(onLeft, onRight))
}
func GetOrElse[E, A, HKTEA, HKTA any](mchain func(HKTEA, func(ET.Either[E, A]) HKTA) HKTA, mof func(A) HKTA, onLeft func(E) HKTA) func(HKTEA) HKTA {
return MatchE(mchain, onLeft, mof)
}
func OrElse[E1, E2, A, HKTE1A, HKTE2A any](mchain func(HKTE1A, func(ET.Either[E1, A]) HKTE2A) HKTE2A, mof func(ET.Either[E2, A]) HKTE2A, onLeft func(E1) HKTE2A) func(HKTE1A) HKTE2A {
return MatchE(mchain, onLeft, F.Flow2(ET.Right[E2, A], mof))
}
func OrLeft[E1, E2, A, HKTE1A, HKTE2, HKTE2A any](
mchain func(HKTE1A, func(ET.Either[E1, A]) HKTE2A) HKTE2A,
mmap func(HKTE2, func(E2) ET.Either[E2, A]) HKTE2A,
mof func(ET.Either[E2, A]) HKTE2A,
onLeft func(E1) HKTE2) func(HKTE1A) HKTE2A {
return F.Bind2nd(mchain, ET.Fold(F.Flow2(onLeft, F.Bind2nd(mmap, ET.Left[A, E2])), F.Flow2(ET.Right[E2, A], mof)))
}
func MonadMapLeft[E, A, B, HKTFA, HKTFB any](fmap func(HKTFA, func(ET.Either[E, A]) ET.Either[B, A]) HKTFB, fa HKTFA, f func(E) B) HKTFB {
return FC.MonadMap(fmap, ET.MonadMapLeft[E, A, B], fa, f)
}

19
internal/eq/eq.go Normal file
View File

@@ -0,0 +1,19 @@
package eq
import (
EQ "github.com/ibm/fp-go/eq"
F "github.com/ibm/fp-go/function"
)
// Eq implements an equals predicate on the basis of `map` and `ap`
func Eq[HKTA, HKTABOOL, HKTBOOL, A any](
fmap func(HKTA, func(A) func(A) bool) HKTABOOL,
fap func(HKTABOOL, HKTA) HKTBOOL,
e EQ.Eq[A],
) func(l, r HKTA) HKTBOOL {
c := F.Curry2(e.Equals)
return func(fl, fr HKTA) HKTBOOL {
return fap(fmap(fl, c), fr)
}
}

37
internal/file/bracket.go Normal file
View File

@@ -0,0 +1,37 @@
package file
import (
F "github.com/ibm/fp-go/function"
)
// 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, // IOEither[E, A]
GB, // IOEither[E, A]
GANY, // IOEither[E, ANY]
EB, // Either[E, B]
A, B, ANY any](
ofeb func(EB) GB,
chainab func(GA, func(A) GB) GB,
chainebb func(GB, func(EB) GB) GB,
chainany func(GANY, func(ANY) GB) GB,
acquire GA,
use func(A) GB,
release func(A, EB) GANY,
) GB {
return chainab(acquire,
func(a A) GB {
return chainebb(use(a), func(eb EB) GB {
return chainany(
release(a, eb),
F.Constant1[ANY](ofeb(eb)),
)
})
})
}

39
internal/file/file.go Normal file
View File

@@ -0,0 +1,39 @@
package file
import (
"bytes"
"context"
"io"
E "github.com/ibm/fp-go/either"
)
type (
readerWithContext struct {
ctx context.Context
delegate io.Reader
}
)
func (rdr *readerWithContext) Read(p []byte) (int, error) {
// check for cancellarion
if err := rdr.ctx.Err(); err != nil {
return 0, err
}
// simply dispatch
return rdr.delegate.Read(p)
}
// MakeReader creates a context aware reader
func MakeReader(ctx context.Context, rdr io.Reader) io.Reader {
return &readerWithContext{ctx, rdr}
}
// ReadAll reads the content of a reader and allows it to be canceled
func ReadAll(ctx context.Context, rdr io.Reader) E.Either[error, []byte] {
return E.TryCatchError(func() ([]byte, error) {
var buffer bytes.Buffer
_, err := io.Copy(&buffer, MakeReader(ctx, rdr))
return buffer.Bytes(), err
})
}

49
internal/file/resource.go Normal file
View File

@@ -0,0 +1,49 @@
package file
import (
F "github.com/ibm/fp-go/function"
)
// WithResource constructs a function that creates a resource, then operates on it and then releases the resource
func WithResource[
GA,
GR,
GANY,
E, R, A, ANY any](
mchain func(GR, func(R) GA) GA,
mfold1 func(GA, func(E) GA, func(A) GA) GA,
mfold2 func(GANY, func(E) GA, func(ANY) GA) GA,
mmap func(GANY, func(ANY) A) GA,
left func(E) GA,
) func(onCreate func() GR, onRelease func(R) GANY) func(func(R) GA) GA {
return func(onCreate func() GR, onRelease func(R) GANY) func(func(R) GA) GA {
return func(f func(R) GA) GA {
return mchain(
onCreate(), func(r R) GA {
// handle errors
return mfold1(
f(r),
func(e E) GA {
// the original error
err := left(e)
// if resource processing produced and error, still release the resource but return the first error
return mfold2(
onRelease(r),
F.Constant1[E](err),
F.Constant1[ANY](err),
)
},
func(a A) GA {
// if resource processing succeeded, release the resource. If this fails return failure, else the original error
return F.Pipe1(
onRelease(r),
F.Bind2nd(mmap, F.Constant1[ANY](a)),
)
})
},
)
}
}
}

View File

@@ -0,0 +1,53 @@
package fromeither
import (
ET "github.com/ibm/fp-go/either"
F "github.com/ibm/fp-go/function"
O "github.com/ibm/fp-go/option"
)
func FromOption[E, A, HKTEA any](fromEither func(ET.Either[E, A]) HKTEA, onNone func() E) func(ma O.Option[A]) HKTEA {
return F.Flow2(ET.FromOption[E, A](onNone), fromEither)
}
func FromPredicate[E, A, HKTEA any](fromEither func(ET.Either[E, A]) HKTEA, pred func(A) bool, onFalse func(A) E) func(A) HKTEA {
return F.Flow2(ET.FromPredicate(pred, onFalse), fromEither)
}
func MonadFromOption[E, A, HKTEA any](
fromEither func(ET.Either[E, A]) HKTEA,
onNone func() E,
ma O.Option[A],
) HKTEA {
return F.Pipe1(
O.MonadFold(
ma,
F.Nullary2(onNone, ET.Left[A, E]),
ET.Right[E, A],
),
fromEither,
)
}
func FromOptionK[E, A, B, HKTEB any](
fromEither func(ET.Either[E, B]) HKTEB,
onNone func() E) func(f func(A) O.Option[B]) func(A) HKTEB {
// helper
return F.Bind2nd(F.Flow2[func(A) O.Option[B], func(O.Option[B]) HKTEB, A, O.Option[B], HKTEB], FromOption(fromEither, onNone))
}
func MonadChainEitherK[A, E, B, HKTEA, HKTEB any](
mchain func(HKTEA, func(A) HKTEB) HKTEB,
fromEither func(ET.Either[E, B]) HKTEB,
ma HKTEA,
f func(A) ET.Either[E, B]) HKTEB {
return mchain(ma, F.Flow2(f, fromEither))
}
func ChainOptionK[A, E, B, HKTEA, HKTEB any](
mchain func(HKTEA, func(A) HKTEB) HKTEB,
fromEither func(ET.Either[E, B]) HKTEB,
onNone func() E,
) func(f func(A) O.Option[B]) func(ma HKTEA) HKTEB {
return F.Flow2(FromOptionK[E, A](fromEither, onNone), F.Bind1st(F.Bind2nd[HKTEA, func(A) HKTEB, HKTEB], mchain))
}

40
internal/fromio/io.go Normal file
View File

@@ -0,0 +1,40 @@
package fromio
import (
F "github.com/ibm/fp-go/function"
C "github.com/ibm/fp-go/internal/chain"
)
func MonadChainFirstIOK[A, B, HKTA, HKTB any, GIOB ~func() B](
mchain func(HKTA, func(A) HKTA) HKTA,
mmap func(HKTB, func(B) A) HKTA,
fromio func(GIOB) HKTB,
first HKTA, f func(A) GIOB) HKTA {
// chain
return C.MonadChainFirst(mchain, mmap, first, F.Flow2(f, fromio))
}
func ChainFirstIOK[A, B, HKTA, HKTB any, GIOB ~func() B](
mchain func(HKTA, func(A) HKTA) HKTA,
mmap func(HKTB, func(B) A) HKTA,
fromio func(GIOB) HKTB,
f func(A) GIOB) func(HKTA) HKTA {
// chain
return C.ChainFirst(mchain, mmap, F.Flow2(f, fromio))
}
func MonadChainIOK[GR ~func() B, A, B, HKTA, HKTB any](
mchain func(HKTA, func(A) HKTB) HKTB,
fromio func(GR) HKTB,
first HKTA, f func(A) GR) HKTB {
// chain
return C.MonadChain[A, B](mchain, first, F.Flow2(f, fromio))
}
func ChainIOK[GR ~func() B, A, B, HKTA, HKTB any](
mchain func(HKTA, func(A) HKTB) HKTB,
fromio func(GR) HKTB,
f func(A) GR) func(HKTA) HKTB {
// chain
return C.Chain[A, B](mchain, F.Flow2(f, fromio))
}

View File

@@ -0,0 +1,11 @@
package functor
import (
F "github.com/ibm/fp-go/function"
)
// HKTFGA = HKT[F, HKT[G, A]]
// HKTFGB = HKT[F, HKT[G, B]]
func MonadMap[A, B, HKTGA, HKTGB, HKTFGA, HKTFGB any](fmap func(HKTFGA, func(HKTGA) HKTGB) HKTFGB, gmap func(HKTGA, func(A) B) HKTGB, fa HKTFGA, f func(A) B) HKTFGB {
return fmap(fa, F.Bind2nd(gmap, f))
}

View File

@@ -27,40 +27,41 @@ HKTB = HKT<B>
HKTAB = HKT<func(A)B>
*/
func traverseWithIndex[MA ~map[K]A, MB ~map[K]B, K comparable, A, B, HKTB, HKTAB, HKTRB any](
_of func(MB) HKTRB,
_map func(HKTRB, func(MB) func(B) MB) HKTAB,
_ap func(HKTAB, HKTB) HKTRB,
fof func(MB) HKTRB,
fmap func(func(MB) func(B) MB) func(HKTRB) HKTAB,
fap func(HKTB) func(HKTAB) HKTRB,
ta MA, f func(K, A) HKTB) HKTRB {
// this function inserts a value into a map with a given key
cb := F.Curry3(addKey[MB, K, B])
mmap := F.Flow2(F.Curry3(addKey[MB, K, B]), fmap)
return ReduceWithIndex(ta, func(k K, r HKTRB, a A) HKTRB {
return _ap(
_map(r, cb(k)),
f(k, a),
return F.Pipe2(
r,
mmap(k),
fap(f(k, a)),
)
}, _of(createEmpty[MB]()))
}, fof(createEmpty[MB]()))
}
func MonadTraverse[MA ~map[K]A, MB ~map[K]B, K comparable, A, B, HKTB, HKTAB, HKTRB any](
_of func(MB) HKTRB,
_map func(HKTRB, func(MB) func(B) MB) HKTAB,
_ap func(HKTAB, HKTB) HKTRB,
fof func(MB) HKTRB,
fmap func(func(MB) func(B) MB) func(HKTRB) HKTAB,
fap func(HKTB) func(HKTAB) HKTRB,
r MA, f func(A) HKTB) HKTRB {
return traverseWithIndex(_of, _map, _ap, r, F.Ignore1of2[K](f))
return traverseWithIndex(fof, fmap, fap, r, F.Ignore1of2[K](f))
}
func TraverseWithIndex[MA ~map[K]A, MB ~map[K]B, K comparable, A, B, HKTB, HKTAB, HKTRB any](
_of func(MB) HKTRB,
_map func(HKTRB, func(MB) func(B) MB) HKTAB,
_ap func(HKTAB, HKTB) HKTRB,
fof func(MB) HKTRB,
fmap func(func(MB) func(B) MB) func(HKTRB) HKTAB,
fap func(HKTB) func(HKTAB) HKTRB,
f func(K, A) HKTB) func(MA) HKTRB {
return func(ma MA) HKTRB {
return traverseWithIndex(_of, _map, _ap, ma, f)
return traverseWithIndex(fof, fmap, fap, ma, f)
}
}
@@ -69,14 +70,14 @@ func TraverseWithIndex[MA ~map[K]A, MB ~map[K]B, K comparable, A, B, HKTB, HKTAB
// HKTAB = HKT<func(A)B>
// HKTRB = HKT<MB>
func Traverse[MA ~map[K]A, MB ~map[K]B, K comparable, A, B, HKTB, HKTAB, HKTRB any](
_of func(MB) HKTRB,
_map func(HKTRB, func(MB) func(B) MB) HKTAB,
_ap func(HKTAB, HKTB) HKTRB,
fof func(MB) HKTRB,
fmap func(func(MB) func(B) MB) func(HKTRB) HKTAB,
fap func(HKTB) func(HKTAB) HKTRB,
f func(A) HKTB) func(MA) HKTRB {
return func(ma MA) HKTRB {
return MonadTraverse(_of, _map, _ap, ma, f)
return MonadTraverse(fof, fmap, fap, ma, f)
}
}
@@ -84,10 +85,10 @@ func Traverse[MA ~map[K]A, MB ~map[K]B, K comparable, A, B, HKTB, HKTAB, HKTRB a
// HKTAA = HKT[func(A)MA]
// HKTRA = HKT[MA]
func Sequence[MA ~map[K]A, MKTA ~map[K]HKTA, K comparable, A, HKTA, HKTAA, HKTRA any](
_of func(MA) HKTRA,
_map func(HKTRA, func(MA) func(A) MA) HKTAA,
_ap func(HKTAA, HKTA) HKTRA,
fof func(MA) HKTRA,
fmap func(func(MA) func(A) MA) func(HKTRA) HKTAA,
fap func(HKTA) func(HKTAA) HKTRA,
ma MKTA) HKTRA {
return MonadTraverse(_of, _map, _ap, ma, F.Identity[HKTA])
return MonadTraverse(fof, fmap, fap, ma, F.Identity[HKTA])
}

15
io/apply.go Normal file
View File

@@ -0,0 +1,15 @@
package io
import (
G "github.com/ibm/fp-go/io/generic"
M "github.com/ibm/fp-go/monoid"
S "github.com/ibm/fp-go/semigroup"
)
func ApplySemigroup[A any](s S.Semigroup[A]) S.Semigroup[IO[A]] {
return G.ApplySemigroup[IO[A]](s)
}
func ApplicativeMonoid[A any](m M.Monoid[A]) M.Monoid[IO[A]] {
return G.ApplicativeMonoid[IO[A]](m)
}

11
io/eq.go Normal file
View File

@@ -0,0 +1,11 @@
package io
import (
EQ "github.com/ibm/fp-go/eq"
G "github.com/ibm/fp-go/io/generic"
)
// Eq implements the equals predicate for values contained in the IO monad
func Eq[A any](e EQ.Eq[A]) EQ.Eq[IO[A]] {
return G.Eq[IO[A]](e)
}

81
io/generic/ap.go Normal file
View File

@@ -0,0 +1,81 @@
package generic
import (
G "github.com/ibm/fp-go/internal/apply"
)
const (
// useParallel is the feature flag to control if we use the parallel or the sequential implementation of ap
useParallel = true
)
// monadApSeq implements the applicative on a single thread by first executing mab and the ma
func monadApSeq[GA ~func() A, GB ~func() B, GAB ~func() func(A) B, A, B any](mab GAB, ma GA) GB {
return MakeIO[GB](func() B {
return mab()(ma())
})
}
// monadApPar implements the applicative on two threads, the main thread executes mab and the actuall
// apply operation and the second thred computes ma. Communication between the threads happens via a channel
func monadApPar[GA ~func() A, GB ~func() B, GAB ~func() func(A) B, A, B any](mab GAB, ma GA) GB {
return MakeIO[GB](func() B {
c := make(chan A)
go func() {
c <- ma()
close(c)
}()
return mab()(<-c)
})
}
// MonadAp implements the `ap` operation. Depending on a feature flag this will be sequential or parallel, the preferred implementation
// is parallel
func MonadAp[GA ~func() A, GB ~func() B, GAB ~func() func(A) B, A, B any](mab GAB, ma GA) GB {
if useParallel {
return monadApPar[GA, GB](mab, ma)
}
return monadApSeq[GA, GB](mab, ma)
}
// MonadApFirst combines two effectful actions, keeping only the result of the first.
func MonadApFirst[GA ~func() A, GB ~func() B, GBA ~func() func(B) A, A, B any](first GA, second GB) GA {
return G.MonadApFirst(
MonadAp[GB, GA, GBA, B, A],
MonadMap[GA, GBA, A, func(B) A],
first,
second,
)
}
// ApFirst combines two effectful actions, keeping only the result of the first.
func ApFirst[GA ~func() A, GB ~func() B, GBA ~func() func(B) A, A, B any](second GB) func(GA) GA {
return G.ApFirst(
MonadAp[GB, GA, GBA, B, A],
MonadMap[GA, GBA, A, func(B) A],
second,
)
}
// MonadApSecond combines two effectful actions, keeping only the result of the second.
func MonadApSecond[GA ~func() A, GB ~func() B, GBB ~func() func(B) B, A, B any](first GA, second GB) GB {
return G.MonadApSecond(
MonadAp[GB, GB, GBB, B, B],
MonadMap[GA, GBB, A, func(B) B],
first,
second,
)
}
// ApSecond combines two effectful actions, keeping only the result of the second.
func ApSecond[GA ~func() A, GB ~func() B, GBB ~func() func(B) B, A, B any](second GB) func(GA) GB {
return G.ApSecond(
MonadAp[GB, GB, GBB, B, B],
MonadMap[GA, GBB, A, func(B) B],
second,
)
}

14
io/generic/apply.go Normal file
View File

@@ -0,0 +1,14 @@
package generic
import (
M "github.com/ibm/fp-go/monoid"
S "github.com/ibm/fp-go/semigroup"
)
func ApplySemigroup[GA ~func() A, A any](s S.Semigroup[A]) S.Semigroup[GA] {
return S.ApplySemigroup(MonadMap[GA, func() func(A) A, A, func(A) A], MonadAp[GA, GA, func() func(A) A, A, A], s)
}
func ApplicativeMonoid[GA ~func() A, A any](m M.Monoid[A]) M.Monoid[GA] {
return M.ApplicativeMonoid(Of[GA, A], MonadMap[GA, func() func(A) A, A, func(A) A], MonadAp[GA, GA, func() func(A) A, A, A], m)
}

20
io/generic/eq.go Normal file
View File

@@ -0,0 +1,20 @@
package generic
import (
EQ "github.com/ibm/fp-go/eq"
G "github.com/ibm/fp-go/internal/eq"
)
// Eq implements the equals predicate for values contained in the IO monad
func Eq[GA ~func() A, A any](e EQ.Eq[A]) EQ.Eq[GA] {
// comparator for the monad
eq := G.Eq(
MonadMap[GA, func() func(A) bool, A, func(A) bool],
MonadAp[GA, func() bool, func() func(A) bool, A, bool],
e,
)
// eagerly execute
return EQ.FromEquals(func(l, r GA) bool {
return eq(l, r)()
})
}

133
io/generic/io.go Normal file
View File

@@ -0,0 +1,133 @@
package generic
import (
"sync"
"time"
F "github.com/ibm/fp-go/function"
C "github.com/ibm/fp-go/internal/chain"
)
// type IO[A any] = func() A
func MakeIO[GA ~func() A, A any](f func() A) GA {
return f
}
func Of[GA ~func() A, A any](a A) GA {
return MakeIO[GA](F.Constant(a))
}
func FromIO[GA ~func() A, A any](a GA) GA {
return a
}
// FromImpure converts a side effect without a return value into a side effect that returns any
func FromImpure[GA ~func() any, IMP ~func()](f IMP) GA {
return MakeIO[GA](func() any {
f()
return nil
})
}
func MonadOf[GA ~func() A, A any](a A) GA {
return MakeIO[GA](F.Constant(a))
}
func MonadMap[GA ~func() A, GB ~func() B, A, B any](fa GA, f func(A) B) GB {
return MakeIO[GB](func() B {
return F.Pipe1(fa(), f)
})
}
func Map[GA ~func() A, GB ~func() B, A, B any](f func(A) B) func(GA) GB {
return F.Bind2nd(MonadMap[GA, GB, A, B], f)
}
func MonadMapTo[GA ~func() A, GB ~func() B, A, B any](fa GA, b B) GB {
return MonadMap[GA, GB](fa, F.Constant1[A](b))
}
func MapTo[GA ~func() A, GB ~func() B, A, B any](b B) func(GA) GB {
return F.Bind2nd(MonadMapTo[GA, GB, A, B], b)
}
// MonadChain composes computations in sequence, using the return value of one computation to determine the next computation.
func MonadChain[GA ~func() A, GB ~func() B, A, B any](fa GA, f func(A) GB) GB {
return MakeIO[GB](func() B {
return F.Pipe1(fa(), f)()
})
}
// Chain composes computations in sequence, using the return value of one computation to determine the next computation.
func Chain[GA ~func() A, GB ~func() B, A, B any](f func(A) GB) func(GA) GB {
return F.Bind2nd(MonadChain[GA, GB, A, B], f)
}
// MonadChainTo composes computations in sequence, ignoring the return value of the first computation
func MonadChainTo[GA ~func() A, GB ~func() B, A, B any](fa GA, fb GB) GB {
return MonadChain(fa, F.Constant1[A](fb))
}
// ChainTo composes computations in sequence, ignoring the return value of the first computation
func ChainTo[GA ~func() A, GB ~func() B, A, B any](fb GB) func(GA) GB {
return F.Bind2nd(MonadChainTo[GA, GB, A, B], fb)
}
// MonadChainFirst composes computations in sequence, using the return value of one computation to determine the next computation and
// keeping only the result of the first.
func MonadChainFirst[GA ~func() A, GB ~func() B, A, B any](fa GA, f func(A) GB) GA {
return C.MonadChainFirst(MonadChain[GA, GA, A, A], MonadMap[GB, GA, B, A], fa, f)
}
// ChainFirst composes computations in sequence, using the return value of one computation to determine the next computation and
// keeping only the result of the first.
func ChainFirst[GA ~func() A, GB ~func() B, A, B any](f func(A) GB) func(GA) GA {
return C.ChainFirst(MonadChain[GA, GA, A, A], MonadMap[GB, GA, B, A], f)
}
func Ap[GA ~func() A, GB ~func() B, GAB ~func() func(A) B, A, B any](ma GA) func(GAB) GB {
return F.Bind2nd(MonadAp[GA, GB, GAB, A, B], ma)
}
func Flatten[GA ~func() A, GAA ~func() GA, A any](mma GAA) GA {
return mma()
}
// Memoize computes the value of the provided IO monad lazily but exactly once
func Memoize[GA ~func() A, A any](ma GA) GA {
// synchronization primitives
var once sync.Once
var result A
// callback
gen := func() {
result = ma()
}
// returns our memoized wrapper
return func() A {
once.Do(gen)
return result
}
}
// Delay creates an operation that passes in the value after some delay
func Delay[GA ~func() A, A any](delay time.Duration) func(GA) GA {
return func(ga GA) GA {
return MakeIO[GA](func() A {
time.Sleep(delay)
return ga()
})
}
}
// Now returns the current timestamp
func Now[GA ~func() time.Time]() GA {
return MakeIO[GA](time.Now)
}
// Defer creates an IO by creating a brand new IO via a generator function, each time
func Defer[GA ~func() A, A any](gen func() GA) GA {
return MakeIO[GA](func() A {
return gen()()
})
}

29
io/generic/logging.go Normal file
View File

@@ -0,0 +1,29 @@
package generic
import (
"log"
Logging "github.com/ibm/fp-go/logging"
)
func Logger[GA ~func() any, A any](loggers ...*log.Logger) func(string) func(A) GA {
_, right := Logging.LoggingCallbacks(loggers...)
return func(prefix string) func(A) GA {
return func(a A) GA {
return FromImpure[GA](func() {
right("%s: %v", prefix, a)
})
}
}
}
func Logf[GA ~func() any, A any](loggers ...*log.Logger) func(string) func(A) GA {
_, right := Logging.LoggingCallbacks(loggers...)
return func(prefix string) func(A) GA {
return func(a A) GA {
return FromImpure[GA](func() {
right(prefix, a)
})
}
}
}

34
io/generic/retry.go Normal file
View File

@@ -0,0 +1,34 @@
package generic
import (
R "github.com/ibm/fp-go/retry"
G "github.com/ibm/fp-go/retry/generic"
)
type retryStatusIO = func() R.RetryStatus
// Retry combinator for actions that don't raise exceptions, but
// signal in their type the outcome has failed. Examples are the
// `Option`, `Either` and `EitherT` monads.
//
// policy - refers to the retry policy
// action - converts a status into an operation to be executed
// check - checks if the result of the action needs to be retried
func Retrying[GA ~func() A, A any](
policy R.RetryPolicy,
action func(R.RetryStatus) GA,
check func(A) bool,
) GA {
// get an implementation for the types
return G.Retrying(
Chain[GA, GA, A, A],
Chain[retryStatusIO, GA, R.RetryStatus, A],
Of[GA, A],
Of[retryStatusIO, R.RetryStatus],
Delay[retryStatusIO, R.RetryStatus],
policy,
action,
check,
)
}

45
io/generic/sequence.go Normal file
View File

@@ -0,0 +1,45 @@
package generic
import (
"github.com/ibm/fp-go/internal/apply"
T "github.com/ibm/fp-go/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[GA ~func() A, GTA ~func() T.Tuple1[A], A any](a GA) GTA {
return apply.SequenceT1(
Map[GA, GTA, A, T.Tuple1[A]],
a,
)
}
func SequenceT2[GA ~func() A, GB ~func() B, GTAB ~func() T.Tuple2[A, B], A, B any](a GA, b GB) GTAB {
return apply.SequenceT2(
Map[GA, func() func(B) T.Tuple2[A, B], A, func(B) T.Tuple2[A, B]],
Ap[GB, GTAB, func() func(B) T.Tuple2[A, B], B, T.Tuple2[A, B]],
a, b,
)
}
func SequenceT3[GA ~func() A, GB ~func() B, GC ~func() C, GTABC ~func() T.Tuple3[A, B, C], A, B, C any](a GA, b GB, c GC) GTABC {
return apply.SequenceT3(
Map[GA, func() func(B) func(C) T.Tuple3[A, B, C], A, func(B) func(C) T.Tuple3[A, B, C]],
Ap[GB, func() func(C) T.Tuple3[A, B, C], func() func(B) func(C) T.Tuple3[A, B, C], B, func(C) T.Tuple3[A, B, C]],
Ap[GC, GTABC, func() func(C) T.Tuple3[A, B, C], C, T.Tuple3[A, B, C]],
a, b, c,
)
}
func SequenceT4[GA ~func() A, GB ~func() B, GC ~func() C, GD ~func() D, GTABCD ~func() T.Tuple4[A, B, C, D], A, B, C, D any](a GA, b GB, c GC, d GD) GTABCD {
return apply.SequenceT4(
Map[GA, func() func(B) func(C) func(D) T.Tuple4[A, B, C, D], A, func(B) func(C) func(D) T.Tuple4[A, B, C, D]],
Ap[GB, func() func(C) func(D) T.Tuple4[A, B, C, D], func() func(B) func(C) func(D) T.Tuple4[A, B, C, D], B, func(C) func(D) T.Tuple4[A, B, C, D]],
Ap[GC, func() func(D) T.Tuple4[A, B, C, D], func() func(C) func(D) T.Tuple4[A, B, C, D], C, func(D) T.Tuple4[A, B, C, D]],
Ap[GD, GTABCD, func() func(D) T.Tuple4[A, B, C, D], D, T.Tuple4[A, B, C, D]],
a, b, c, d,
)
}

56
io/generic/traverse.go Normal file
View File

@@ -0,0 +1,56 @@
package generic
import (
F "github.com/ibm/fp-go/function"
RA "github.com/ibm/fp-go/internal/array"
RR "github.com/ibm/fp-go/internal/record"
)
func MonadTraverseArray[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](tas AAS, f func(A) GB) GBS {
return RA.MonadTraverse(
Of[GBS, BBS],
Map[GBS, func() func(B) BBS, BBS, func(B) BBS],
Ap[GB, GBS, func() func(B) BBS, B, BBS],
tas,
f,
)
}
func TraverseArray[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](f func(A) GB) func(AAS) GBS {
return RA.Traverse[AAS](
Of[GBS, BBS],
Map[GBS, func() func(B) BBS, BBS, func(B) BBS],
Ap[GB, GBS, func() func(B) BBS, B, BBS],
f,
)
}
func SequenceArray[GA ~func() A, GAS ~func() AAS, AAS ~[]A, GAAS ~[]GA, A any](tas GAAS) GAS {
return MonadTraverseArray[GA, GAS](tas, F.Identity[GA])
}
// MonadTraverseRecord transforms a record using an IO transform an IO of a record
func MonadTraverseRecord[GB ~func() B, GBS ~func() MB, MA ~map[K]A, MB ~map[K]B, K comparable, A, B any](ma MA, f func(A) GB) GBS {
return RR.MonadTraverse[MA](
Of[GBS, MB],
Map[GBS, func() func(B) MB, MB, func(B) MB],
Ap[GB, GBS, func() func(B) MB, B, MB],
ma, f,
)
}
// TraverseRecord transforms a record using an IO transform an IO of a record
func TraverseRecord[GB ~func() B, GBS ~func() MB, MA ~map[K]A, MB ~map[K]B, K comparable, A, B any](f func(A) GB) func(MA) GBS {
return RR.Traverse[MA](
Of[GBS, MB],
Map[GBS, func() func(B) MB, MB, func(B) MB],
Ap[GB, GBS, func() func(B) MB, B, MB],
f,
)
}
func SequenceRecord[GA ~func() A, GAS ~func() AAS, AAS ~map[K]A, GAAS ~map[K]GA, K comparable, A any](tas GAAS) GAS {
return MonadTraverseRecord[GA, GAS](tas, F.Identity[GA])
}

125
io/io.go Normal file
View File

@@ -0,0 +1,125 @@
package io
import (
"time"
G "github.com/ibm/fp-go/io/generic"
)
// IO represents a synchronous computation that cannot fail
// refer to [https://andywhite.xyz/posts/2021-01-27-rte-foundations/#ioltagt] for more details
type IO[A any] func() A
func MakeIO[A any](f func() A) IO[A] {
return G.MakeIO[IO[A]](f)
}
func Of[A any](a A) IO[A] {
return G.Of[IO[A]](a)
}
func FromIO[A any](a IO[A]) IO[A] {
return G.FromIO(a)
}
// FromImpure converts a side effect without a return value into a side effect that returns any
func FromImpure(f func()) IO[any] {
return G.FromImpure[IO[any]](f)
}
func MonadOf[A any](a A) IO[A] {
return G.MonadOf[IO[A]](a)
}
func MonadMap[A, B any](fa IO[A], f func(A) B) IO[B] {
return G.MonadMap[IO[A], IO[B]](fa, f)
}
func Map[A, B any](f func(A) B) func(fa IO[A]) IO[B] {
return G.Map[IO[A], IO[B]](f)
}
func MonadMapTo[A, B any](fa IO[A], b B) IO[B] {
return G.MonadMapTo[IO[A], IO[B]](fa, b)
}
func MapTo[A, B any](b B) func(IO[A]) IO[B] {
return G.MapTo[IO[A], IO[B]](b)
}
// MonadChain composes computations in sequence, using the return value of one computation to determine the next computation.
func MonadChain[A, B any](fa IO[A], f func(A) IO[B]) IO[B] {
return G.MonadChain(fa, f)
}
// Chain composes computations in sequence, using the return value of one computation to determine the next computation.
func Chain[A, B any](f func(A) IO[B]) func(IO[A]) IO[B] {
return G.Chain[IO[A]](f)
}
func MonadAp[B, A any](mab IO[func(A) B], ma IO[A]) IO[B] {
return G.MonadAp[IO[A], IO[B]](mab, ma)
}
func Ap[B, A any](ma IO[A]) func(IO[func(A) B]) IO[B] {
return G.Ap[IO[A], IO[B], IO[func(A) B]](ma)
}
func Flatten[A any](mma IO[IO[A]]) IO[A] {
return G.Flatten(mma)
}
// Memoize computes the value of the provided IO monad lazily but exactly once
func Memoize[A any](ma IO[A]) IO[A] {
return G.Memoize(ma)
}
// MonadChainFirst composes computations in sequence, using the return value of one computation to determine the next computation and
// keeping only the result of the first.
func MonadChainFirst[A, B any](fa IO[A], f func(A) IO[B]) IO[A] {
return G.MonadChainFirst(fa, f)
}
// ChainFirst composes computations in sequence, using the return value of one computation to determine the next computation and
// keeping only the result of the first.
func ChainFirst[A, B any](f func(A) IO[B]) func(IO[A]) IO[A] {
return G.ChainFirst[IO[A]](f)
}
// MonadApFirst combines two effectful actions, keeping only the result of the first.
func MonadApFirst[A, B any](first IO[A], second IO[B]) IO[A] {
return G.MonadApFirst[IO[A], IO[B], IO[func(B) A]](first, second)
}
// ApFirst combines two effectful actions, keeping only the result of the first.
func ApFirst[A, B any](second IO[B]) func(IO[A]) IO[A] {
return G.ApFirst[IO[A], IO[B], IO[func(B) A]](second)
}
// MonadApSecond combines two effectful actions, keeping only the result of the second.
func MonadApSecond[A, B any](first IO[A], second IO[B]) IO[B] {
return G.MonadApSecond[IO[A], IO[B], IO[func(B) B]](first, second)
}
// ApSecond combines two effectful actions, keeping only the result of the second.
func ApSecond[A, B any](second IO[B]) func(IO[A]) IO[B] {
return G.ApSecond[IO[A], IO[B], IO[func(B) B]](second)
}
// MonadChainTo composes computations in sequence, ignoring the return value of the first computation
func MonadChainTo[A, B any](fa IO[A], fb IO[B]) IO[B] {
return G.MonadChainTo(fa, fb)
}
// ChainTo composes computations in sequence, ignoring the return value of the first computation
func ChainTo[A, B any](fb IO[B]) func(IO[A]) IO[B] {
return G.ChainTo[IO[A]](fb)
}
// Now returns the current timestamp
var Now = G.Now[IO[time.Time]]()
// Defer creates an IO by creating a brand new IO via a generator function, each time
func Defer[A any](gen func() IO[A]) IO[A] {
return G.Defer[IO[A]](gen)
}

58
io/io_test.go Normal file
View File

@@ -0,0 +1,58 @@
package io
import (
"math/rand"
"testing"
F "github.com/ibm/fp-go/function"
"github.com/ibm/fp-go/internal/utils"
"github.com/stretchr/testify/assert"
)
func TestMap(t *testing.T) {
assert.Equal(t, 2, F.Pipe1(Of(1), Map(utils.Double))())
}
func TestChain(t *testing.T) {
f := func(n int) IO[int] {
return Of(n * 2)
}
assert.Equal(t, 2, F.Pipe1(Of(1), Chain(f))())
}
func TestAp(t *testing.T) {
assert.Equal(t, 2, F.Pipe1(Of(utils.Double), Ap[int, int](Of(1)))())
}
func TestFlatten(t *testing.T) {
assert.Equal(t, 1, F.Pipe1(Of(Of(1)), Flatten[int])())
}
func TestMemoize(t *testing.T) {
data := Memoize(MakeIO(rand.Int))
value1 := data()
value2 := data()
assert.Equal(t, value1, value2)
}
func TestApFirst(t *testing.T) {
x := F.Pipe1(
Of("a"),
ApFirst[string](Of("b")),
)
assert.Equal(t, "a", x())
}
func TestApSecond(t *testing.T) {
x := F.Pipe1(
Of("a"),
ApSecond[string](Of("b")),
)
assert.Equal(t, "b", x())
}

18
io/logging.go Normal file
View File

@@ -0,0 +1,18 @@
package io
import (
"log"
G "github.com/ibm/fp-go/io/generic"
)
// Logger constructs a logger function that can be used with ChainXXXIOK
func Logger[A any](loggers ...*log.Logger) func(string) func(A) IO[any] {
return G.Logger[IO[any], A](loggers...)
}
// Logf constructs a logger function that can be used with ChainXXXIOK
// the string prefix contains the format string for the log value
func Logf[A any](loggers ...*log.Logger) func(string) func(A) IO[any] {
return G.Logf[IO[any], A](loggers...)
}

25
io/logging_test.go Normal file
View File

@@ -0,0 +1,25 @@
package io
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestLogger(t *testing.T) {
l := Logger[int]()
lio := l("out")
assert.Equal(t, nil, lio(10)())
}
func TestLogf(t *testing.T) {
l := Logf[int]()
lio := l("Value is %d")
assert.Equal(t, nil, lio(10)())
}

19
io/retry.go Normal file
View File

@@ -0,0 +1,19 @@
package io
import (
G "github.com/ibm/fp-go/io/generic"
R "github.com/ibm/fp-go/retry"
)
// Retrying will retry the actions according to the check policy
//
// policy - refers to the retry policy
// action - converts a status into an operation to be executed
// check - checks if the result of the action needs to be retried
func Retrying[A any](
policy R.RetryPolicy,
action func(R.RetryStatus) IO[A],
check func(A) bool,
) IO[A] {
return G.Retrying(policy, action, check)
}

32
io/retry_test.go Normal file
View File

@@ -0,0 +1,32 @@
package io
import (
"fmt"
"strings"
"testing"
"time"
R "github.com/ibm/fp-go/retry"
"github.com/stretchr/testify/assert"
)
var expLogBackoff = R.ExponentialBackoff(10)
// our retry policy with a 1s cap
var testLogPolicy = R.CapDelay(
2*time.Second,
R.Monoid.Concat(expLogBackoff, R.LimitRetries(20)),
)
func TestRetry(t *testing.T) {
action := func(status R.RetryStatus) IO[string] {
return Of(fmt.Sprintf("Retrying %d", status.IterNumber))
}
check := func(value string) bool {
return !strings.Contains(value, "5")
}
r := Retrying(testLogPolicy, action, check)
assert.Equal(t, "Retrying 5", r())
}

24
io/sequence.go Normal file
View File

@@ -0,0 +1,24 @@
package io
import (
G "github.com/ibm/fp-go/io/generic"
T "github.com/ibm/fp-go/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 IO[A]) IO[T.Tuple1[A]] {
return G.SequenceT1[IO[A], IO[T.Tuple1[A]]](a)
}
func SequenceT2[A, B any](a IO[A], b IO[B]) IO[T.Tuple2[A, B]] {
return G.SequenceT2[IO[A], IO[B], IO[T.Tuple2[A, B]]](a, b)
}
func SequenceT3[A, B, C any](a IO[A], b IO[B], c IO[C]) IO[T.Tuple3[A, B, C]] {
return G.SequenceT3[IO[A], IO[B], IO[C], IO[T.Tuple3[A, B, C]]](a, b, c)
}
func SequenceT4[A, B, C, D any](a IO[A], b IO[B], c IO[C], d IO[D]) IO[T.Tuple4[A, B, C, D]] {
return G.SequenceT4[IO[A], IO[B], IO[C], IO[D], IO[T.Tuple4[A, B, C, D]]](a, b, c, d)
}

59
io/testing/laws.go Normal file
View File

@@ -0,0 +1,59 @@
package testing
import (
"testing"
EQ "github.com/ibm/fp-go/eq"
L "github.com/ibm/fp-go/internal/monad/testing"
"github.com/ibm/fp-go/io"
)
// AssertLaws asserts the apply monad laws for the `Either` 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,
io.Eq(eqa),
io.Eq(eqb),
io.Eq(eqc),
io.Of[A],
io.Of[B],
io.Of[C],
io.Of[func(A) A],
io.Of[func(A) B],
io.Of[func(B) C],
io.Of[func(func(A) B) B],
io.MonadMap[A, A],
io.MonadMap[A, B],
io.MonadMap[A, C],
io.MonadMap[B, C],
io.MonadMap[func(B) C, func(func(A) B) func(A) C],
io.MonadChain[A, A],
io.MonadChain[A, B],
io.MonadChain[A, C],
io.MonadChain[B, C],
io.MonadAp[A, A],
io.MonadAp[B, A],
io.MonadAp[C, B],
io.MonadAp[C, A],
io.MonadAp[B, func(A) B],
io.MonadAp[func(A) C, func(A) B],
ab,
bc,
)
}

32
io/testing/laws_test.go Normal file
View File

@@ -0,0 +1,32 @@
package testing
import (
"fmt"
"testing"
EQ "github.com/ibm/fp-go/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))
}

35
io/traverse.go Normal file
View File

@@ -0,0 +1,35 @@
package io
import (
G "github.com/ibm/fp-go/io/generic"
)
func MonadTraverseArray[A, B any](tas []A, f func(A) IO[B]) IO[[]B] {
return G.MonadTraverseArray[IO[B], IO[[]B]](tas, f)
}
// TraverseArray applies a function returning an [IO] to all elements in an array and the
// transforms this into an [IO] of that array
func TraverseArray[A, B any](f func(A) IO[B]) func([]A) IO[[]B] {
return G.TraverseArray[IO[B], IO[[]B], []A](f)
}
// SequenceArray converts an array of [IO] to an [IO] of an array
func SequenceArray[A any](tas []IO[A]) IO[[]A] {
return G.SequenceArray[IO[A], IO[[]A]](tas)
}
func MonadTraverseRecord[K comparable, A, B any](tas map[K]A, f func(A) IO[B]) IO[map[K]B] {
return G.MonadTraverseRecord[IO[B], IO[map[K]B]](tas, f)
}
// TraverseArray applies a function returning an [IO] to all elements in a record and the
// transforms this into an [IO] of that record
func TraverseRecord[K comparable, A, B any](f func(A) IO[B]) func(map[K]A) IO[map[K]B] {
return G.TraverseRecord[IO[B], IO[map[K]B], map[K]A](f)
}
// SequenceRecord converts a record of [IO] to an [IO] of a record
func SequenceRecord[K comparable, A any](tas map[K]IO[A]) IO[map[K]A] {
return G.SequenceRecord[IO[A], IO[map[K]A]](tas)
}

25
ioeither/ap.go Normal file
View File

@@ -0,0 +1,25 @@
package ioeither
import (
G "github.com/ibm/fp-go/ioeither/generic"
)
// MonadApFirst combines two effectful actions, keeping only the result of the first.
func MonadApFirst[E, A, B any](first IOEither[E, A], second IOEither[E, B]) IOEither[E, A] {
return G.MonadApFirst[IOEither[E, A], IOEither[E, B], IOEither[E, func(B) A]](first, second)
}
// ApFirst combines two effectful actions, keeping only the result of the first.
func ApFirst[E, A, B any](second IOEither[E, B]) func(IOEither[E, A]) IOEither[E, A] {
return G.ApFirst[IOEither[E, A], IOEither[E, B], IOEither[E, func(B) A]](second)
}
// MonadApSecond combines two effectful actions, keeping only the result of the second.
func MonadApSecond[E, A, B any](first IOEither[E, A], second IOEither[E, B]) IOEither[E, B] {
return G.MonadApSecond[IOEither[E, A], IOEither[E, B], IOEither[E, func(B) B]](first, second)
}
// ApSecond combines two effectful actions, keeping only the result of the second.
func ApSecond[E, A, B any](second IOEither[E, B]) func(IOEither[E, A]) IOEither[E, B] {
return G.ApSecond[IOEither[E, A], IOEither[E, B], IOEither[E, func(B) B]](second)
}

16
ioeither/bracket.go Normal file
View File

@@ -0,0 +1,16 @@
package ioeither
import (
ET "github.com/ibm/fp-go/either"
G "github.com/ibm/fp-go/ioeither/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[E, A, B, ANY any](
acquire IOEither[E, A],
use func(A) IOEither[E, B],
release func(A, ET.Either[E, B]) IOEither[E, ANY],
) IOEither[E, B] {
return G.Bracket(acquire, use, release)
}

17
ioeither/eq.go Normal file
View File

@@ -0,0 +1,17 @@
package ioeither
import (
ET "github.com/ibm/fp-go/either"
EQ "github.com/ibm/fp-go/eq"
G "github.com/ibm/fp-go/ioeither/generic"
)
// Eq implements the equals predicate for values contained in the IOEither monad
func Eq[E, A any](eq EQ.Eq[ET.Either[E, A]]) EQ.Eq[IOEither[E, A]] {
return G.Eq[IOEither[E, A]](eq)
}
// FromStrictEquals constructs an `Eq` from the canonical comparison function
func FromStrictEquals[E, A comparable]() EQ.Eq[IOEither[E, A]] {
return G.FromStrictEquals[IOEither[E, A]]()
}

30
ioeither/eq_test.go Normal file
View File

@@ -0,0 +1,30 @@
package ioeither
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestEq(t *testing.T) {
r1 := Of[string](1)
r2 := Of[string](1)
r3 := Of[string](2)
e1 := Left[int]("a")
e2 := Left[int]("a")
e3 := Left[int]("b")
eq := FromStrictEquals[string, int]()
assert.True(t, eq.Equals(r1, r1))
assert.True(t, eq.Equals(r1, r2))
assert.False(t, eq.Equals(r1, r3))
assert.False(t, eq.Equals(r1, e1))
assert.True(t, eq.Equals(e1, e1))
assert.True(t, eq.Equals(e1, e2))
assert.False(t, eq.Equals(e1, e3))
assert.False(t, eq.Equals(e2, r2))
}

13
ioeither/exec/exec.go Normal file
View File

@@ -0,0 +1,13 @@
package exec
import (
"github.com/ibm/fp-go/exec"
F "github.com/ibm/fp-go/function"
IOE "github.com/ibm/fp-go/ioeither"
G "github.com/ibm/fp-go/ioeither/generic"
)
var (
// Command executes a command
Command = F.Curry3(G.Command[IOE.IOEither[error, exec.CommandOutput]])
)

View File

@@ -0,0 +1,28 @@
package exec
import (
"strings"
"testing"
RA "github.com/ibm/fp-go/array"
B "github.com/ibm/fp-go/bytes"
E "github.com/ibm/fp-go/either"
"github.com/ibm/fp-go/exec"
F "github.com/ibm/fp-go/function"
IOE "github.com/ibm/fp-go/ioeither"
"github.com/stretchr/testify/assert"
)
func TestOpenSSL(t *testing.T) {
// execute the openSSL binary
version := F.Pipe1(
Command("openssl")(RA.From("version"))(B.Monoid.Empty()),
IOE.Map[error](F.Flow3(
exec.StdOut,
B.ToString,
strings.TrimSpace,
)),
)
assert.True(t, E.IsRight(version()))
}

13
ioeither/file/close.go Normal file
View File

@@ -0,0 +1,13 @@
package file
import (
"io"
IOE "github.com/ibm/fp-go/ioeither"
)
func onClose[R io.Closer](r R) IOE.IOEither[error, R] {
return IOE.TryCatchError(func() (R, error) {
return r, r.Close()
})
}

22
ioeither/file/file.go Normal file
View File

@@ -0,0 +1,22 @@
package file
import (
"os"
IOE "github.com/ibm/fp-go/ioeither"
)
var (
// Open opens a file for reading
Open = IOE.Eitherize1(os.Open)
// ReadFile reads the context of a file
ReadFile = IOE.Eitherize1(os.ReadFile)
// WriteFile writes a data blob to a file
WriteFile = func(dstName string, perm os.FileMode) func([]byte) IOE.IOEither[error, []byte] {
return func(data []byte) IOE.IOEither[error, []byte] {
return IOE.TryCatchError(func() ([]byte, error) {
return data, os.WriteFile(dstName, data, perm)
})
}
}
)

22
ioeither/file/readall.go Normal file
View File

@@ -0,0 +1,22 @@
package file
import (
"io"
IOE "github.com/ibm/fp-go/ioeither"
)
func onReadAll[R io.Reader](r R) IOE.IOEither[error, []byte] {
return IOE.TryCatchError(func() ([]byte, error) {
return io.ReadAll(r)
})
}
// ReadAll uses a generator function to create a stream, reads it and closes it
func ReadAll[R io.ReadCloser](acquire IOE.IOEither[error, R]) IOE.IOEither[error, []byte] {
return IOE.WithResource[error, R, []byte](
acquire,
onClose[R])(
onReadAll[R],
)
}

35
ioeither/file/write.go Normal file
View File

@@ -0,0 +1,35 @@
package file
import (
"io"
IOE "github.com/ibm/fp-go/ioeither"
)
func onWriteAll[W io.Writer](data []byte) func(w W) IOE.IOEither[error, []byte] {
return func(w W) IOE.IOEither[error, []byte] {
return IOE.TryCatchError(func() ([]byte, error) {
_, err := w.Write(data)
return data, err
})
}
}
// 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 IOE.IOEither[error, W]) IOE.IOEither[error, []byte] {
onWrite := onWriteAll[W](data)
return func(onCreate IOE.IOEither[error, W]) IOE.IOEither[error, []byte] {
return IOE.WithResource[error, W, []byte](
onCreate,
onClose[W])(
onWrite,
)
}
}
// Write uses a generator function to create a stream, writes data to it and closes it
func Write[W io.WriteCloser, R any](acquire IOE.IOEither[error, W]) func(use func(W) IOE.IOEither[error, R]) IOE.IOEither[error, R] {
return IOE.WithResource[error, W, R](
acquire,
onClose[W])
}

48
ioeither/generic/ap.go Normal file
View File

@@ -0,0 +1,48 @@
package generic
import (
ET "github.com/ibm/fp-go/either"
G "github.com/ibm/fp-go/internal/apply"
)
// MonadApFirst combines two effectful actions, keeping only the result of the first.
func MonadApFirst[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GBA ~func() ET.Either[E, func(B) A], E, A, B any](first GA, second GB) GA {
return G.MonadApFirst(
MonadAp[GB, GA, GBA, E, B, A],
MonadMap[GA, GBA, E, A, func(B) A],
first,
second,
)
}
// ApFirst combines two effectful actions, keeping only the result of the first.
func ApFirst[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GBA ~func() ET.Either[E, func(B) A], E, A, B any](second GB) func(GA) GA {
return G.ApFirst(
MonadAp[GB, GA, GBA, E, B, A],
MonadMap[GA, GBA, E, A, func(B) A],
second,
)
}
// MonadApSecond combines two effectful actions, keeping only the result of the second.
func MonadApSecond[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GBB ~func() ET.Either[E, func(B) B], E, A, B any](first GA, second GB) GB {
return G.MonadApSecond(
MonadAp[GB, GB, GBB, E, B, B],
MonadMap[GA, GBB, E, A, func(B) B],
first,
second,
)
}
// ApSecond combines two effectful actions, keeping only the result of the second.
func ApSecond[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GBB ~func() ET.Either[E, func(B) B], E, A, B any](second GB) func(GA) GB {
return G.ApSecond(
MonadAp[GB, GB, GBB, E, B, B],
MonadMap[GA, GBB, E, A, func(B) B],
second,
)
}

View File

@@ -0,0 +1,31 @@
package generic
import (
ET "github.com/ibm/fp-go/either"
G "github.com/ibm/fp-go/internal/file"
I "github.com/ibm/fp-go/io/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() ET.Either[E, A],
GB ~func() ET.Either[E, B],
GANY ~func() ET.Either[E, ANY],
E, A, B, ANY any](
acquire GA,
use func(A) GB,
release func(A, ET.Either[E, B]) GANY,
) GB {
return G.Bracket[GA, GB, GANY, ET.Either[E, B], A, B](
I.Of[GB, ET.Either[E, B]],
MonadChain[GA, GB, E, A, B],
I.MonadChain[GB, GB, ET.Either[E, B], ET.Either[E, B]],
MonadChain[GANY, GB, E, ANY, B],
acquire,
use,
release,
)
}

17
ioeither/generic/eq.go Normal file
View File

@@ -0,0 +1,17 @@
package generic
import (
ET "github.com/ibm/fp-go/either"
EQ "github.com/ibm/fp-go/eq"
G "github.com/ibm/fp-go/io/generic"
)
// Eq implements the equals predicate for values contained in the IOEither monad
func Eq[GA ~func() ET.Either[E, A], E, A any](eq EQ.Eq[ET.Either[E, A]]) EQ.Eq[GA] {
return G.Eq[GA](eq)
}
// FromStrictEquals constructs an `Eq` from the canonical comparison function
func FromStrictEquals[GA ~func() ET.Either[E, A], E, A comparable]() EQ.Eq[GA] {
return Eq[GA](ET.FromStrictEquals[E, A]())
}

16
ioeither/generic/exec.go Normal file
View File

@@ -0,0 +1,16 @@
package generic
import (
"context"
ET "github.com/ibm/fp-go/either"
"github.com/ibm/fp-go/exec"
GE "github.com/ibm/fp-go/internal/exec"
)
// Command executes a command
func Command[GA ~func() ET.Either[error, exec.CommandOutput]](name string, args []string, in []byte) GA {
return TryCatchError[GA](func() (exec.CommandOutput, error) {
return GE.Exec(context.Background(), name, args, in)
})
}

View File

@@ -0,0 +1,328 @@
package generic
import (
"time"
ET "github.com/ibm/fp-go/either"
"github.com/ibm/fp-go/errors"
F "github.com/ibm/fp-go/function"
C "github.com/ibm/fp-go/internal/chain"
"github.com/ibm/fp-go/internal/eithert"
FE "github.com/ibm/fp-go/internal/fromeither"
FI "github.com/ibm/fp-go/internal/fromio"
IO "github.com/ibm/fp-go/io/generic"
O "github.com/ibm/fp-go/option"
)
// type IOEither[E, A any] = func() Either[E, A]
func MakeIO[GA ~func() ET.Either[E, A], E, A any](f GA) GA {
return f
}
func Left[GA ~func() ET.Either[E, A], E, A any](l E) GA {
return MakeIO(eithert.Left(IO.MonadOf[GA, ET.Either[E, A]], l))
}
func Right[GA ~func() ET.Either[E, A], E, A any](r A) GA {
return MakeIO(eithert.Right(IO.MonadOf[GA, ET.Either[E, A]], r))
}
func Of[GA ~func() ET.Either[E, A], E, A any](r A) GA {
return Right[GA](r)
}
func MonadOf[GA ~func() ET.Either[E, A], E, A any](r A) GA {
return Of[GA](r)
}
func LeftIO[GA ~func() ET.Either[E, A], GE ~func() E, E, A any](ml GE) GA {
return MakeIO(eithert.LeftF(IO.MonadMap[GE, GA, E, ET.Either[E, A]], ml))
}
func RightIO[GA ~func() ET.Either[E, A], GR ~func() A, E, A any](mr GR) GA {
return MakeIO(eithert.RightF(IO.MonadMap[GR, GA, A, ET.Either[E, A]], mr))
}
func FromEither[GA ~func() ET.Either[E, A], E, A any](e ET.Either[E, A]) GA {
return IO.Of[GA](e)
}
func FromOption[GA ~func() ET.Either[E, A], E, A any](onNone func() E) func(o O.Option[A]) GA {
return FE.FromOption(
FromEither[GA, E, A],
onNone,
)
}
func ChainOptionK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](onNone func() E) func(func(A) O.Option[B]) func(GA) GB {
return FE.ChainOptionK(
MonadChain[GA, GB, E, A, B],
FromEither[GB, E, B],
onNone,
)
}
func FromIO[GA ~func() ET.Either[E, A], GR ~func() A, E, A any](mr GR) GA {
return RightIO[GA](mr)
}
func MonadMap[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fa GA, f func(A) B) GB {
return eithert.MonadMap(IO.MonadMap[GA, GB, ET.Either[E, A], ET.Either[E, B]], fa, f)
}
func Map[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](f func(A) B) func(GA) GB {
return F.Bind2nd(MonadMap[GA, GB, E, A, B], f)
}
func MonadMapTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fa GA, b B) GB {
return MonadMap[GA, GB](fa, F.Constant1[A](b))
}
func MapTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](b B) func(GA) GB {
return F.Bind2nd(MonadMapTo[GA, GB, E, A, B], b)
}
func MonadChain[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fa GA, f func(A) GB) GB {
return eithert.MonadChain(IO.MonadChain[GA, GB, ET.Either[E, A], ET.Either[E, B]], IO.MonadOf[GB, ET.Either[E, B]], fa, f)
}
func Chain[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](f func(A) GB) func(GA) GB {
return F.Bind2nd(MonadChain[GA, GB, E, A, B], f)
}
func MonadChainTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fa GA, fb GB) GB {
return MonadChain(fa, F.Constant1[A](fb))
}
func ChainTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fb GB) func(GA) GB {
return F.Bind2nd(MonadChainTo[GA, GB, E, A, B], fb)
}
func MonadChainEitherK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](ma GA, f func(A) ET.Either[E, B]) GB {
return FE.MonadChainEitherK(
MonadChain[GA, GB, E, A, B],
FromEither[GB, E, B],
ma,
f,
)
}
func MonadChainIOK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GR ~func() B, E, A, B any](ma GA, f func(A) GR) GB {
return FI.MonadChainIOK(
MonadChain[GA, GB, E, A, B],
FromIO[GB, GR, E, B],
ma,
f,
)
}
func ChainIOK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GR ~func() B, E, A, B any](f func(A) GR) func(GA) GB {
return FI.ChainIOK(
MonadChain[GA, GB, E, A, B],
FromIO[GB, GR, E, B],
f,
)
}
func ChainEitherK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](f func(A) ET.Either[E, B]) func(GA) GB {
return F.Bind2nd(MonadChainEitherK[GA, GB, E, A, B], f)
}
func MonadAp[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], E, A, B any](mab GAB, ma GA) GB {
return eithert.MonadAp(
IO.MonadAp[GA, GB, func() func(ET.Either[E, A]) ET.Either[E, B], ET.Either[E, A], ET.Either[E, B]],
IO.MonadMap[GAB, func() func(ET.Either[E, A]) ET.Either[E, B], ET.Either[E, func(A) B], func(ET.Either[E, A]) ET.Either[E, B]],
mab, ma)
}
func Ap[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], E, A, B any](ma GA) func(GAB) GB {
return F.Bind2nd(MonadAp[GA, GB, GAB, E, A, B], ma)
}
func Flatten[GA ~func() ET.Either[E, A], GAA ~func() ET.Either[E, GA], E, A any](mma GAA) GA {
return MonadChain(mma, F.Identity[GA])
}
func TryCatch[GA ~func() ET.Either[E, A], E, A any](f func() (A, error), onThrow func(error) E) GA {
return MakeIO(func() ET.Either[E, A] {
return ET.TryCatch(f, onThrow)
})
}
func TryCatchError[GA ~func() ET.Either[error, A], A any](f func() (A, error)) GA {
return TryCatch[GA](f, errors.IdentityError)
}
func Eitherize0[GEA ~func() ET.Either[error, A], GA ~func() (A, error), A any](f GA) func() GEA {
ef := ET.Eitherize0(f)
return func() GEA {
return MakeIO(ef)
}
}
func Uneitherize0[GEA ~func() ET.Either[error, A], GTA ~func() GEA, A any](f GTA) func() (A, error) {
return func() (A, error) {
return ET.Unwrap(f()())
}
}
func Eitherize1[GEA ~func() ET.Either[error, A], GA ~func(t1 T1) (A, error), T1, A any](f GA) func(T1) GEA {
ef := ET.Eitherize1(f)
return func(t1 T1) GEA {
return MakeIO[GEA](func() ET.Either[error, A] {
return ef(t1)
})
}
}
func Uneitherize1[GEA ~func() ET.Either[error, A], GTA ~func(t1 T1) GEA, T1, A any](f GTA) func(T1) (A, error) {
return func(t1 T1) (A, error) {
return ET.Unwrap(f(t1)())
}
}
func Eitherize2[GEA ~func() ET.Either[error, A], GA ~func(t1 T1, t2 T2) (A, error), T1, T2, A any](f GA) func(T1, T2) GEA {
ef := ET.Eitherize2(f)
return func(t1 T1, t2 T2) GEA {
return MakeIO[GEA](func() ET.Either[error, A] {
return ef(t1, t2)
})
}
}
func Uneitherize2[GEA ~func() ET.Either[error, A], GTA ~func(t1 T1, t2 T2) GEA, T1, T2, A any](f GTA) func(T1, T2) (A, error) {
return func(t1 T1, t2 T2) (A, error) {
return ET.Unwrap(f(t1, t2)())
}
}
func Eitherize3[GEA ~func() ET.Either[error, A], GA ~func(t1 T1, t2 T2, t3 T3) (A, error), T1, T2, T3, A any](f GA) func(T1, T2, T3) GEA {
ef := ET.Eitherize3(f)
return func(t1 T1, t2 T2, t3 T3) GEA {
return MakeIO[GEA](func() ET.Either[error, A] {
return ef(t1, t2, t3)
})
}
}
func Uneitherize3[GEA ~func() ET.Either[error, A], GTA ~func(t1 T1, t2 T2, t3 T3) GEA, T1, T2, T3, A any](f GTA) func(T1, T2, T3) (A, error) {
return func(t1 T1, t2 T2, t3 T3) (A, error) {
return ET.Unwrap(f(t1, t2, t3)())
}
}
func Eitherize4[GEA ~func() ET.Either[error, A], GA ~func(t1 T1, t2 T2, t3 T3, t4 T4) (A, error), T1, T2, T3, T4, A any](f GA) func(T1, T2, T3, T4) GEA {
ef := ET.Eitherize4(f)
return func(t1 T1, t2 T2, t3 T3, t4 T4) GEA {
return MakeIO[GEA](func() ET.Either[error, A] {
return ef(t1, t2, t3, t4)
})
}
}
func Uneitherize4[GEA ~func() ET.Either[error, A], GTA ~func(t1 T1, t2 T2, t3 T3, t4 T4) GEA, T1, T2, T3, T4, A any](f GTA) func(T1, T2, T3, T4) (A, error) {
return func(t1 T1, t2 T2, t3 T3, t4 T4) (A, error) {
return ET.Unwrap(f(t1, t2, t3, t4)())
}
}
// Memoize computes the value of the provided IO monad lazily but exactly once
func Memoize[GA ~func() ET.Either[E, A], E, A any](ma GA) GA {
return IO.Memoize(ma)
}
func MonadMapLeft[GA1 ~func() ET.Either[E1, A], GA2 ~func() ET.Either[E2, A], E1, E2, A any](fa GA1, f func(E1) E2) GA2 {
return eithert.MonadMapLeft(IO.MonadMap[GA1, GA2, ET.Either[E1, A], ET.Either[E2, A]], fa, f)
}
func MapLeft[GA1 ~func() ET.Either[E1, A], GA2 ~func() ET.Either[E2, A], E1, E2, A any](f func(E1) E2) func(GA1) GA2 {
return F.Bind2nd(MonadMapLeft[GA1, GA2, E1, E2, A], f)
}
// Delay creates an operation that passes in the value after some delay
func Delay[GA ~func() ET.Either[E, A], E, A any](delay time.Duration) func(GA) GA {
return IO.Delay[GA](delay)
}
func MonadBiMap[GA ~func() ET.Either[E1, A], GB ~func() ET.Either[E2, B], E1, E2, A, B any](fa GA, f func(E1) E2, g func(A) B) GB {
return eithert.MonadBiMap(IO.MonadMap[GA, GB, ET.Either[E1, A], ET.Either[E2, B]], fa, f, g)
}
// BiMap maps a pair of functions over the two type arguments of the bifunctor.
func BiMap[GA ~func() ET.Either[E1, A], GB ~func() ET.Either[E2, B], E1, E2, A, B any](f func(E1) E2, g func(A) B) func(GA) GB {
return eithert.BiMap(IO.MonadMap[GA, GB, ET.Either[E1, A], ET.Either[E2, B]], f, g)
}
// Fold convers an IOEither into an IO
func Fold[GA ~func() ET.Either[E, A], GB ~func() B, E, A, B any](onLeft func(E) GB, onRight func(A) GB) func(GA) GB {
return eithert.MatchE(IO.MonadChain[GA, GB, ET.Either[E, A], B], onLeft, onRight)
}
func MonadFold[GA ~func() ET.Either[E, A], GB ~func() B, E, A, B any](ma GA, onLeft func(E) GB, onRight func(A) GB) GB {
return eithert.FoldE(IO.MonadChain[GA, GB, ET.Either[E, A], B], ma, onLeft, onRight)
}
// GetOrElse extracts the value or maps the error
func GetOrElse[GA ~func() ET.Either[E, A], GB ~func() A, E, A any](onLeft func(E) GB) func(GA) GB {
return eithert.GetOrElse(IO.MonadChain[GA, GB, ET.Either[E, A], A], IO.MonadOf[GB, A], onLeft)
}
// MonadChainFirst runs the monad returned by the function but returns the result of the original monad
func MonadChainFirst[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](ma GA, f func(A) GB) GA {
return C.MonadChainFirst(
MonadChain[GA, GA, E, A, A],
MonadMap[GB, GA, E, B, A],
ma,
f,
)
}
// ChainFirst runs the monad returned by the function but returns the result of the original monad
func ChainFirst[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](f func(A) GB) func(GA) GA {
return C.ChainFirst(
MonadChain[GA, GA, E, A, A],
MonadMap[GB, GA, E, B, A],
f,
)
}
// MonadChainFirstIOK runs the monad returned by the function but returns the result of the original monad
func MonadChainFirstIOK[GA ~func() ET.Either[E, A], GIOB ~func() B, E, A, B any](first GA, f func(A) GIOB) GA {
return FI.MonadChainFirstIOK(
MonadChain[GA, GA, E, A, A],
MonadMap[func() ET.Either[E, B], GA, E, B, A],
FromIO[func() ET.Either[E, B], GIOB, E, B],
first,
f,
)
}
// ChainFirstIOK runs the monad returned by the function but returns the result of the original monad
func ChainFirstIOK[GA ~func() ET.Either[E, A], GIOB ~func() B, E, A, B any](f func(A) GIOB) func(GA) GA {
return FI.ChainFirstIOK(
MonadChain[GA, GA, E, A, A],
MonadMap[func() ET.Either[E, B], GA, E, B, A],
FromIO[func() ET.Either[E, B], GIOB, E, B],
f,
)
}
// Swap changes the order of type parameters
func Swap[GEA ~func() ET.Either[E, A], GAE ~func() ET.Either[A, E], E, A any](val GEA) GAE {
return MonadFold(val, Right[GAE], Left[GAE])
}
// FromImpure converts a side effect without a return value into a side effect that returns any
func FromImpure[GA ~func() ET.Either[E, any], IMP ~func(), E any](f IMP) GA {
return F.Pipe2(
f,
IO.FromImpure[func() any, IMP],
FromIO[GA, func() any],
)
}
// Defer creates an IO by creating a brand new IO via a generator function, each time
func Defer[GEA ~func() ET.Either[E, A], E, A any](gen func() GEA) GEA {
return IO.Defer[GEA](gen)
}

View File

@@ -0,0 +1,22 @@
package generic
import (
ET "github.com/ibm/fp-go/either"
F "github.com/ibm/fp-go/function"
IF "github.com/ibm/fp-go/internal/file"
)
// WithResource constructs a function that creates a resource, then operates on it and then releases the resource
func WithResource[
GA ~func() ET.Either[E, A],
GR ~func() ET.Either[E, R],
GANY ~func() ET.Either[E, ANY],
E, R, A, ANY any](onCreate GR, onRelease func(R) GANY) func(func(R) GA) GA {
return IF.WithResource(
MonadChain[GR, GA, E, R, A],
MonadFold[GA, GA, E, A, ET.Either[E, A]],
MonadFold[GANY, GA, E, ANY, ET.Either[E, A]],
MonadMap[GANY, GA, E, ANY, A],
Left[GA, E, A],
)(F.Constant(onCreate), onRelease)
}

23
ioeither/generic/retry.go Normal file
View File

@@ -0,0 +1,23 @@
package generic
import (
ET "github.com/ibm/fp-go/either"
GIO "github.com/ibm/fp-go/io/generic"
R "github.com/ibm/fp-go/retry"
)
// Retry combinator for actions that don't raise exceptions, but
// signal in their type the outcome has failed. Examples are the
// `Option`, `Either` and `EitherT` monads.
//
// policy - refers to the retry policy
// action - converts a status into an operation to be executed
// check - checks if the result of the action needs to be retried
func Retrying[GA ~func() ET.Either[E, A], E, A any](
policy R.RetryPolicy,
action func(R.RetryStatus) GA,
check func(ET.Either[E, A]) bool,
) GA {
// get an implementation for the types
return GIO.Retrying(policy, action, check)
}

View File

@@ -0,0 +1,47 @@
package generic
import (
ET "github.com/ibm/fp-go/either"
"github.com/ibm/fp-go/internal/apply"
T "github.com/ibm/fp-go/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[GA ~func() ET.Either[E, A], GTA ~func() ET.Either[E, T.Tuple1[A]], E, A any](a GA) GTA {
return apply.SequenceT1(
Map[GA, GTA, E, A, T.Tuple1[A]],
a,
)
}
func SequenceT2[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 {
return apply.SequenceT2(
Map[GA, func() ET.Either[E, func(B) T.Tuple2[A, B]], E, A, func(B) T.Tuple2[A, B]],
Ap[GB, GTAB, func() ET.Either[E, func(B) T.Tuple2[A, B]], E, B, T.Tuple2[A, B]],
a, b,
)
}
func SequenceT3[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GC ~func() ET.Either[E, C], GTABC ~func() ET.Either[E, T.Tuple3[A, B, C]], E, A, B, C any](a GA, b GB, c GC) GTABC {
return apply.SequenceT3(
Map[GA, func() ET.Either[E, func(B) func(C) T.Tuple3[A, B, C]], E, A, func(B) func(C) T.Tuple3[A, B, C]],
Ap[GB, func() ET.Either[E, func(C) T.Tuple3[A, B, C]], func() ET.Either[E, func(B) func(C) T.Tuple3[A, B, C]], E, B, func(C) T.Tuple3[A, B, C]],
Ap[GC, GTABC, func() ET.Either[E, func(C) T.Tuple3[A, B, C]], E, C, T.Tuple3[A, B, C]],
a, b, c,
)
}
func SequenceT4[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GC ~func() ET.Either[E, C], GD ~func() ET.Either[E, D], GTABCD ~func() ET.Either[E, T.Tuple4[A, B, C, D]], E, A, B, C, D any](a GA, b GB, c GC, d GD) GTABCD {
return apply.SequenceT4(
Map[GA, func() ET.Either[E, func(B) func(C) func(D) T.Tuple4[A, B, C, D]], E, A, func(B) func(C) func(D) T.Tuple4[A, B, C, D]],
Ap[GB, func() ET.Either[E, func(C) func(D) T.Tuple4[A, B, C, D]], func() ET.Either[E, func(B) func(C) func(D) T.Tuple4[A, B, C, D]], E, B, func(C) func(D) T.Tuple4[A, B, C, D]],
Ap[GC, func() ET.Either[E, func(D) T.Tuple4[A, B, C, D]], func() ET.Either[E, func(C) func(D) T.Tuple4[A, B, C, D]], E, C, func(D) T.Tuple4[A, B, C, D]],
Ap[GD, GTABCD, func() ET.Either[E, func(D) T.Tuple4[A, B, C, D]], E, D, T.Tuple4[A, B, C, D]],
a, b, c, d,
)
}

View File

@@ -0,0 +1,64 @@
package generic
import (
ET "github.com/ibm/fp-go/either"
F "github.com/ibm/fp-go/function"
RA "github.com/ibm/fp-go/internal/array"
RR "github.com/ibm/fp-go/internal/record"
)
// MonadTraverseArray transforms an array
func MonadTraverseArray[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BBS], AAS ~[]A, BBS ~[]B, E, A, B any](tas AAS, f func(A) GB) GBS {
return RA.MonadTraverse[AAS](
Of[GBS, E, BBS],
Map[GBS, func() ET.Either[E, func(B) BBS], E, BBS, func(B) BBS],
Ap[GB, GBS, func() ET.Either[E, func(B) BBS], E, B, BBS],
tas,
f,
)
}
// TraverseArray transforms an array
func TraverseArray[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BBS], AAS ~[]A, BBS ~[]B, E, A, B any](f func(A) GB) func(AAS) GBS {
return RA.Traverse[AAS](
Of[GBS, E, BBS],
Map[GBS, func() ET.Either[E, func(B) BBS], E, BBS, func(B) BBS],
Ap[GB, GBS, func() ET.Either[E, func(B) BBS], E, B, BBS],
f,
)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[GA ~func() ET.Either[E, A], GAS ~func() ET.Either[E, AAS], AAS ~[]A, GAAS ~[]GA, E, A any](tas GAAS) GAS {
return MonadTraverseArray[GA, GAS](tas, F.Identity[GA])
}
// MonadTraverseRecord transforms an array
func MonadTraverseRecord[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BBS], AAS ~map[K]A, BBS ~map[K]B, K comparable, E, A, B any](tas AAS, f func(A) GB) GBS {
return RR.MonadTraverse[AAS](
Of[GBS, E, BBS],
Map[GBS, func() ET.Either[E, func(B) BBS], E, BBS, func(B) BBS],
Ap[GB, GBS, func() ET.Either[E, func(B) BBS], E, B, BBS],
tas,
f,
)
}
// TraverseRecord transforms an array
func TraverseRecord[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BBS], AAS ~map[K]A, BBS ~map[K]B, K comparable, E, A, B any](f func(A) GB) func(AAS) GBS {
return RR.Traverse[AAS](
Of[GBS, E, BBS],
Map[GBS, func() ET.Either[E, func(B) BBS], E, BBS, func(B) BBS],
Ap[GB, GBS, func() ET.Either[E, func(B) BBS], E, B, BBS],
f,
)
}
// SequenceRecord converts a homogeneous sequence of either into an either of sequence
func SequenceRecord[GA ~func() ET.Either[E, A], GAS ~func() ET.Either[E, AAS], AAS ~map[K]A, GAAS ~map[K]GA, K comparable, E, A any](tas GAAS) GAS {
return MonadTraverseRecord[GA, GAS](tas, F.Identity[GA])
}

58
ioeither/http/request.go Normal file
View File

@@ -0,0 +1,58 @@
package http
import (
"io"
"net/http"
B "github.com/ibm/fp-go/bytes"
ER "github.com/ibm/fp-go/errors"
F "github.com/ibm/fp-go/function"
IOE "github.com/ibm/fp-go/ioeither"
IOEF "github.com/ibm/fp-go/ioeither/file"
J "github.com/ibm/fp-go/json"
)
type Client interface {
Do(req *http.Request) IOE.IOEither[error, *http.Response]
}
type client struct {
delegate *http.Client
}
func (client client) Do(req *http.Request) IOE.IOEither[error, *http.Response] {
return IOE.TryCatch(func() (*http.Response, error) {
return client.delegate.Do(req)
}, ER.IdentityError)
}
func MakeClient(httpClient *http.Client) Client {
return client{delegate: httpClient}
}
func ReadAll(client Client) func(*http.Request) IOE.IOEither[error, []byte] {
return func(req *http.Request) IOE.IOEither[error, []byte] {
return IOEF.ReadAll(F.Pipe2(
req,
client.Do,
IOE.Map[error](func(resp *http.Response) io.ReadCloser {
return resp.Body
}),
),
)
}
}
func ReadText(client Client) func(*http.Request) IOE.IOEither[error, string] {
return F.Flow2(
ReadAll(client),
IOE.Map[error](B.ToString),
)
}
func ReadJson[A any](client Client) func(*http.Request) IOE.IOEither[error, A] {
return F.Flow2(
ReadAll(client),
IOE.ChainEitherK(J.Unmarshal[A]),
)
}

View File

@@ -0,0 +1,58 @@
package http
import (
"net"
"net/http"
"testing"
"time"
AR "github.com/ibm/fp-go/array"
E "github.com/ibm/fp-go/either"
HE "github.com/ibm/fp-go/either/http"
"github.com/ibm/fp-go/errors"
F "github.com/ibm/fp-go/function"
IOE "github.com/ibm/fp-go/ioeither"
O "github.com/ibm/fp-go/option"
R "github.com/ibm/fp-go/retry"
"github.com/stretchr/testify/assert"
)
var expLogBackoff = R.ExponentialBackoff(250 * time.Millisecond)
// our retry policy with a 1s cap
var testLogPolicy = R.CapDelay(
2*time.Second,
R.Monoid.Concat(expLogBackoff, R.LimitRetries(20)),
)
type PostItem struct {
UserId uint `json:"userId"`
Id uint `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
}
func TestRetryHttp(t *testing.T) {
// URLs to try, the first URLs have an invalid hostname
urls := AR.From("https://jsonplaceholder1.typicode.com/posts/1", "https://jsonplaceholder2.typicode.com/posts/1", "https://jsonplaceholder3.typicode.com/posts/1", "https://jsonplaceholder4.typicode.com/posts/1", "https://jsonplaceholder.typicode.com/posts/1")
client := MakeClient(&http.Client{})
action := func(status R.RetryStatus) IOE.IOEither[error, *PostItem] {
return F.Pipe2(
HE.GetRequest(urls[status.IterNumber]),
IOE.FromEither[error, *http.Request],
IOE.Chain(ReadJson[*PostItem](client)),
)
}
check := E.Fold(
F.Flow2(
errors.As[*net.DNSError](),
O.Fold(F.Constant(false), F.Constant1[*net.DNSError](true)),
),
F.Constant1[*PostItem](false),
)
item := IOE.Retrying(testLogPolicy, action, check)()
assert.True(t, E.IsRight(item))
}

217
ioeither/ioeither.go Normal file
View File

@@ -0,0 +1,217 @@
package ioeither
import (
ET "github.com/ibm/fp-go/either"
I "github.com/ibm/fp-go/io"
G "github.com/ibm/fp-go/ioeither/generic"
O "github.com/ibm/fp-go/option"
)
// IO represents a synchronous computation that may fail
// refer to [https://andywhite.xyz/posts/2021-01-27-rte-foundations/#ioeitherlte-agt] for more details
type IOEither[E, A any] I.IO[ET.Either[E, A]]
func MakeIO[E, A any](f IOEither[E, A]) IOEither[E, A] {
return G.MakeIO(f)
}
func Left[A, E any](l E) IOEither[E, A] {
return G.Left[IOEither[E, A]](l)
}
func Right[E, A any](r A) IOEither[E, A] {
return G.Right[IOEither[E, A]](r)
}
func Of[E, A any](r A) IOEither[E, A] {
return G.Of[IOEither[E, A]](r)
}
func MonadOf[E, A any](r A) IOEither[E, A] {
return G.MonadOf[IOEither[E, A]](r)
}
func LeftIO[A, E any](ml I.IO[E]) IOEither[E, A] {
return G.LeftIO[IOEither[E, A]](ml)
}
func RightIO[E, A any](mr I.IO[A]) IOEither[E, A] {
return G.RightIO[IOEither[E, A]](mr)
}
func FromEither[E, A any](e ET.Either[E, A]) IOEither[E, A] {
return G.FromEither[IOEither[E, A]](e)
}
func FromOption[A, E any](onNone func() E) func(o O.Option[A]) IOEither[E, A] {
return G.FromOption[IOEither[E, A]](onNone)
}
func ChainOptionK[A, B, E any](onNone func() E) func(func(A) O.Option[B]) func(IOEither[E, A]) IOEither[E, B] {
return G.ChainOptionK[IOEither[E, A], IOEither[E, B]](onNone)
}
func MonadChainIOK[E, A, B any](ma IOEither[E, A], f func(A) I.IO[B]) IOEither[E, B] {
return G.MonadChainIOK[IOEither[E, A], IOEither[E, B]](ma, f)
}
func ChainIOK[E, A, B any](f func(A) I.IO[B]) func(IOEither[E, A]) IOEither[E, B] {
return G.ChainIOK[IOEither[E, A], IOEither[E, B]](f)
}
func FromIO[E, A any](mr I.IO[A]) IOEither[E, A] {
return G.FromIO[IOEither[E, A]](mr)
}
func MonadMap[E, A, B any](fa IOEither[E, A], f func(A) B) IOEither[E, B] {
return G.MonadMap[IOEither[E, A], IOEither[E, B]](fa, f)
}
func Map[E, A, B any](f func(A) B) func(IOEither[E, A]) IOEither[E, B] {
return G.Map[IOEither[E, A], IOEither[E, B]](f)
}
func MonadMapTo[E, A, B any](fa IOEither[E, A], b B) IOEither[E, B] {
return G.MonadMapTo[IOEither[E, A], IOEither[E, B]](fa, b)
}
func MapTo[E, A, B any](b B) func(IOEither[E, A]) IOEither[E, B] {
return G.MapTo[IOEither[E, A], IOEither[E, B]](b)
}
func MonadChain[E, A, B any](fa IOEither[E, A], f func(A) IOEither[E, B]) IOEither[E, B] {
return G.MonadChain(fa, f)
}
func Chain[E, A, B any](f func(A) IOEither[E, B]) func(IOEither[E, A]) IOEither[E, B] {
return G.Chain[IOEither[E, A]](f)
}
func MonadChainEitherK[E, A, B any](ma IOEither[E, A], f func(A) ET.Either[E, B]) IOEither[E, B] {
return G.MonadChainEitherK[IOEither[E, A], IOEither[E, B]](ma, f)
}
func ChainEitherK[E, A, B any](f func(A) ET.Either[E, B]) func(IOEither[E, A]) IOEither[E, B] {
return G.ChainEitherK[IOEither[E, A], IOEither[E, B]](f)
}
func MonadAp[B, E, A any](mab IOEither[E, func(A) B], ma IOEither[E, A]) IOEither[E, B] {
return G.MonadAp[IOEither[E, A], IOEither[E, B]](mab, ma)
}
func Ap[B, E, A any](ma IOEither[E, A]) func(IOEither[E, func(A) B]) IOEither[E, B] {
return G.Ap[IOEither[E, A], IOEither[E, B], IOEither[E, func(A) B]](ma)
}
func Flatten[E, A any](mma IOEither[E, IOEither[E, A]]) IOEither[E, A] {
return G.Flatten(mma)
}
func TryCatch[E, A any](f func() (A, error), onThrow func(error) E) IOEither[E, A] {
return G.TryCatch[IOEither[E, A]](f, onThrow)
}
func TryCatchError[A any](f func() (A, error)) IOEither[error, A] {
return G.TryCatchError[IOEither[error, A]](f)
}
func Eitherize0[A any](f func() (A, error)) func() IOEither[error, A] {
return G.Eitherize0[IOEither[error, A]](f)
}
func Eitherize1[T1, A any](f func(t1 T1) (A, error)) func(T1) IOEither[error, A] {
return G.Eitherize1[IOEither[error, A]](f)
}
func Eitherize2[T1, T2, A any](f func(t1 T1, t2 T2) (A, error)) func(T1, T2) IOEither[error, A] {
return G.Eitherize2[IOEither[error, A]](f)
}
func Eitherize3[T1, T2, T3, A any](f func(t1 T1, t2 T2, t3 T3) (A, error)) func(T1, T2, T3) IOEither[error, A] {
return G.Eitherize3[IOEither[error, A]](f)
}
func Eitherize4[T1, T2, T3, T4, A any](f func(t1 T1, t2 T2, t3 T3, t4 T4) (A, error)) func(T1, T2, T3, T4) IOEither[error, A] {
return G.Eitherize4[IOEither[error, A]](f)
}
func Memoize[E, A any](ma IOEither[E, A]) IOEither[E, A] {
return G.Memoize(ma)
}
func MonadMapLeft[E1, E2, A any](fa IOEither[E1, A], f func(E1) E2) IOEither[E2, A] {
return G.MonadMapLeft[IOEither[E1, A], IOEither[E2, A]](fa, f)
}
func MapLeft[E1, E2, A any](f func(E1) E2) func(IOEither[E1, A]) IOEither[E2, A] {
return G.MapLeft[IOEither[E1, A], IOEither[E2, A]](f)
}
func MonadBiMap[E1, E2, A, B any](fa IOEither[E1, A], f func(E1) E2, g func(A) B) IOEither[E2, B] {
return G.MonadBiMap[IOEither[E1, A], IOEither[E2, B]](fa, f, g)
}
// BiMap maps a pair of functions over the two type arguments of the bifunctor.
func BiMap[E1, E2, A, B any](f func(E1) E2, g func(A) B) func(IOEither[E1, A]) IOEither[E2, B] {
return G.BiMap[IOEither[E1, A], IOEither[E2, B]](f, g)
}
// Fold converts an IOEither into an IO
func Fold[E, A, B any](onLeft func(E) I.IO[B], onRight func(A) I.IO[B]) func(IOEither[E, A]) I.IO[B] {
return G.Fold[IOEither[E, A]](onLeft, onRight)
}
// GetOrElse extracts the value or maps the error
func GetOrElse[E, A any](onLeft func(E) I.IO[A]) func(IOEither[E, A]) I.IO[A] {
return G.GetOrElse[IOEither[E, A]](onLeft)
}
// MonadChainTo composes to the second monad ignoring the return value of the first
func MonadChainTo[E, A, B any](fa IOEither[E, A], fb IOEither[E, B]) IOEither[E, B] {
return G.MonadChainTo(fa, fb)
}
// ChainTo composes to the second monad ignoring the return value of the first
func ChainTo[E, A, B any](fb IOEither[E, B]) func(IOEither[E, A]) IOEither[E, B] {
return G.ChainTo[IOEither[E, A]](fb)
}
// MonadChainFirst runs the monad returned by the function but returns the result of the original monad
func MonadChainFirst[E, A, B any](ma IOEither[E, A], f func(A) IOEither[E, B]) IOEither[E, A] {
return G.MonadChainFirst(ma, f)
}
// ChainFirst runs the monad returned by the function but returns the result of the original monad
func ChainFirst[E, A, B any](f func(A) IOEither[E, B]) func(IOEither[E, A]) IOEither[E, A] {
return G.ChainFirst[IOEither[E, A]](f)
}
// MonadChainFirstIOK runs the monad returned by the function but returns the result of the original monad
func MonadChainFirstIOK[E, A, B any](ma IOEither[E, A], f func(A) I.IO[B]) IOEither[E, A] {
return G.MonadChainFirstIOK(ma, f)
}
// ChainFirsIOKt runs the monad returned by the function but returns the result of the original monad
func ChainFirstIOK[E, A, B any](f func(A) I.IO[B]) func(IOEither[E, A]) IOEither[E, A] {
return G.ChainFirstIOK[IOEither[E, A]](f)
}
// WithResource constructs a function that creates a resource, then operates on it and then releases the resource
func WithResource[E, R, A, ANY any](onCreate IOEither[E, R], onRelease func(R) IOEither[E, ANY]) func(func(R) IOEither[E, A]) IOEither[E, A] {
return G.WithResource[IOEither[E, A]](onCreate, onRelease)
}
// Swap changes the order of type parameters
func Swap[E, A any](val IOEither[E, A]) IOEither[A, E] {
return G.Swap[IOEither[E, A], IOEither[A, E]](val)
}
// FromImpure converts a side effect without a return value into a side effect that returns any
func FromImpure[E any](f func()) IOEither[E, any] {
return G.FromImpure[IOEither[E, any]](f)
}
// Defer creates an IO by creating a brand new IO via a generator function, each time
func Defer[E, A any](gen func() IOEither[E, A]) IOEither[E, A] {
return G.Defer[IOEither[E, A]](gen)
}

121
ioeither/ioeither_test.go Normal file
View File

@@ -0,0 +1,121 @@
package ioeither
import (
"fmt"
"testing"
E "github.com/ibm/fp-go/either"
F "github.com/ibm/fp-go/function"
"github.com/ibm/fp-go/internal/utils"
I "github.com/ibm/fp-go/io"
IG "github.com/ibm/fp-go/io/generic"
O "github.com/ibm/fp-go/option"
"github.com/stretchr/testify/assert"
)
func TestMap(t *testing.T) {
assert.Equal(t, E.Of[error](2), F.Pipe1(
Of[error](1),
Map[error](utils.Double),
)())
}
func TestChainEitherK(t *testing.T) {
f := ChainEitherK(func(n int) E.Either[string, int] {
if n > 0 {
return E.Of[string](n)
}
return E.Left[int]("a")
})
assert.Equal(t, E.Right[string](1), f(Right[string](1))())
assert.Equal(t, E.Left[int]("a"), f(Right[string](-1))())
assert.Equal(t, E.Left[int]("b"), f(Left[int]("b"))())
}
func TestChainOptionK(t *testing.T) {
f := ChainOptionK[int, int](F.Constant("a"))(func(n int) O.Option[int] {
if n > 0 {
return O.Some(n)
}
return O.None[int]()
})
assert.Equal(t, E.Right[string](1), f(Right[string](1))())
assert.Equal(t, E.Left[int]("a"), f(Right[string](-1))())
assert.Equal(t, E.Left[int]("b"), f(Left[int]("b"))())
}
func TestFromOption(t *testing.T) {
f := FromOption[int](F.Constant("a"))
assert.Equal(t, E.Right[string](1), f(O.Some(1))())
assert.Equal(t, E.Left[int]("a"), f(O.None[int]())())
}
func TestChainIOK(t *testing.T) {
f := ChainIOK[string](func(n int) I.IO[string] {
return I.MakeIO(func() string {
return fmt.Sprintf("%d", n)
})
})
assert.Equal(t, E.Right[string]("1"), f(Right[string](1))())
assert.Equal(t, E.Left[string, string]("b"), f(Left[int]("b"))())
}
func TestChainWithIO(t *testing.T) {
r := F.Pipe1(
Of[error]("test"),
// sad, we need the generics version ...
IG.Map[IOEither[error, string], I.IO[bool]](E.IsRight[error, string]),
)
assert.True(t, r())
}
func TestChainFirst(t *testing.T) {
f := func(a string) IOEither[string, int] {
if len(a) > 2 {
return Of[string](len(a))
}
return Left[int]("foo")
}
good := Of[string]("foo")
bad := Of[string]("a")
ch := ChainFirst(f)
assert.Equal(t, E.Of[string]("foo"), F.Pipe1(good, ch)())
assert.Equal(t, E.Left[string, string]("foo"), F.Pipe1(bad, ch)())
}
func TestChainFirstIOK(t *testing.T) {
f := func(a string) I.IO[int] {
return I.Of(len(a))
}
good := Of[string]("foo")
ch := ChainFirstIOK[string](f)
assert.Equal(t, E.Of[string]("foo"), F.Pipe1(good, ch)())
}
func TestApFirst(t *testing.T) {
x := F.Pipe1(
Of[error]("a"),
ApFirst[error, string](Of[error]("b")),
)
assert.Equal(t, E.Of[error]("a"), x())
}
func TestApSecond(t *testing.T) {
x := F.Pipe1(
Of[error]("a"),
ApSecond[error, string](Of[error]("b")),
)
assert.Equal(t, E.Of[error]("b"), x())
}

20
ioeither/retry.go Normal file
View File

@@ -0,0 +1,20 @@
package ioeither
import (
ET "github.com/ibm/fp-go/either"
G "github.com/ibm/fp-go/ioeither/generic"
R "github.com/ibm/fp-go/retry"
)
// Retrying will retry the actions according to the check policy
//
// policy - refers to the retry policy
// action - converts a status into an operation to be executed
// check - checks if the result of the action needs to be retried
func Retrying[E, A any](
policy R.RetryPolicy,
action func(R.RetryStatus) IOEither[E, A],
check func(ET.Either[E, A]) bool,
) IOEither[E, A] {
return G.Retrying(policy, action, check)
}

33
ioeither/retry_test.go Normal file
View File

@@ -0,0 +1,33 @@
package ioeither
import (
"fmt"
"testing"
"time"
E "github.com/ibm/fp-go/either"
R "github.com/ibm/fp-go/retry"
"github.com/stretchr/testify/assert"
)
var expLogBackoff = R.ExponentialBackoff(10 * time.Millisecond)
// our retry policy with a 1s cap
var testLogPolicy = R.CapDelay(
2*time.Second,
R.Monoid.Concat(expLogBackoff, R.LimitRetries(20)),
)
func TestRetry(t *testing.T) {
action := func(status R.RetryStatus) IOEither[error, string] {
if status.IterNumber < 5 {
return Left[string](fmt.Errorf("retrying %d", status.IterNumber))
}
return Of[error](fmt.Sprintf("Retrying %d", status.IterNumber))
}
check := E.IsLeft[error, string]
r := Retrying(testLogPolicy, action, check)
assert.Equal(t, E.Of[error]("Retrying 5"), r())
}

54
ioeither/sequence.go Normal file
View File

@@ -0,0 +1,54 @@
package ioeither
import (
G "github.com/ibm/fp-go/ioeither/generic"
T "github.com/ibm/fp-go/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[E, A any](a IOEither[E, A]) IOEither[E, T.Tuple1[A]] {
return G.SequenceT1[
IOEither[E, A],
IOEither[E, T.Tuple1[A]],
](a)
}
func SequenceT2[E, A, B any](
a IOEither[E, A],
b IOEither[E, B],
) IOEither[E, T.Tuple2[A, B]] {
return G.SequenceT2[
IOEither[E, A],
IOEither[E, B],
IOEither[E, T.Tuple2[A, B]],
](a, b)
}
func SequenceT3[E, A, B, C any](
a IOEither[E, A],
b IOEither[E, B],
c IOEither[E, C],
) IOEither[E, T.Tuple3[A, B, C]] {
return G.SequenceT3[
IOEither[E, A],
IOEither[E, B],
IOEither[E, C],
IOEither[E, T.Tuple3[A, B, C]],
](a, b, c)
}
func SequenceT4[E, A, B, C, D any](
a IOEither[E, A],
b IOEither[E, B],
c IOEither[E, C],
d IOEither[E, D],
) IOEither[E, T.Tuple4[A, B, C, D]] {
return G.SequenceT4[
IOEither[E, A],
IOEither[E, B],
IOEither[E, C],
IOEither[E, D],
IOEither[E, T.Tuple4[A, B, C, D]],
](a, b, c, d)
}

61
ioeither/testing/laws.go Normal file
View File

@@ -0,0 +1,61 @@
package testing
import (
"testing"
ET "github.com/ibm/fp-go/either"
EQ "github.com/ibm/fp-go/eq"
L "github.com/ibm/fp-go/internal/monad/testing"
IOE "github.com/ibm/fp-go/ioeither"
)
// AssertLaws asserts the apply monad laws for the `IOEither` monad
func AssertLaws[E, A, B, C any](t *testing.T,
eqe EQ.Eq[E],
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,
IOE.Eq(ET.Eq(eqe, eqa)),
IOE.Eq(ET.Eq(eqe, eqb)),
IOE.Eq(ET.Eq(eqe, eqc)),
IOE.Of[E, A],
IOE.Of[E, B],
IOE.Of[E, C],
IOE.Of[E, func(A) A],
IOE.Of[E, func(A) B],
IOE.Of[E, func(B) C],
IOE.Of[E, func(func(A) B) B],
IOE.MonadMap[E, A, A],
IOE.MonadMap[E, A, B],
IOE.MonadMap[E, A, C],
IOE.MonadMap[E, B, C],
IOE.MonadMap[E, func(B) C, func(func(A) B) func(A) C],
IOE.MonadChain[E, A, A],
IOE.MonadChain[E, A, B],
IOE.MonadChain[E, A, C],
IOE.MonadChain[E, B, C],
IOE.MonadAp[A, E, A],
IOE.MonadAp[B, E, A],
IOE.MonadAp[C, E, B],
IOE.MonadAp[C, E, A],
IOE.MonadAp[B, E, func(A) B],
IOE.MonadAp[func(A) C, E, func(A) B],
ab,
bc,
)
}

View File

@@ -0,0 +1,33 @@
package testing
import (
"fmt"
"testing"
EQ "github.com/ibm/fp-go/eq"
"github.com/stretchr/testify/assert"
)
func TestMonadLaws(t *testing.T) {
// some comparison
eqe := EQ.FromStrictEquals[string]()
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, eqe, eqa, eqb, eqc, ab, bc)
assert.True(t, laws(true))
assert.True(t, laws(false))
}

25
ioeither/traverse.go Normal file
View File

@@ -0,0 +1,25 @@
package ioeither
import (
G "github.com/ibm/fp-go/ioeither/generic"
)
// TraverseArray transforms an array
func TraverseArray[E, A, B any](f func(A) IOEither[E, B]) func([]A) IOEither[E, []B] {
return G.TraverseArray[IOEither[E, B], IOEither[E, []B], []A](f)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[E, A any](ma []IOEither[E, A]) IOEither[E, []A] {
return G.SequenceArray[IOEither[E, A], IOEither[E, []A]](ma)
}
// TraverseRecord transforms a record
func TraverseRecord[K comparable, E, A, B any](f func(A) IOEither[E, B]) func(map[K]A) IOEither[E, map[K]B] {
return G.TraverseRecord[IOEither[E, B], IOEither[E, map[K]B], map[K]A](f)
}
// SequenceRecord converts a homogeneous sequence of either into an either of sequence
func SequenceRecord[K comparable, E, A any](ma map[K]IOEither[E, A]) IOEither[E, map[K]A] {
return G.SequenceRecord[IOEither[E, A], IOEither[E, map[K]A]](ma)
}

23
json/json.go Normal file
View File

@@ -0,0 +1,23 @@
package json
import (
"encoding/json"
E "github.com/ibm/fp-go/either"
)
// Unmarshal parses a JSON data structure from bytes
func Unmarshal[A any](data []byte) E.Either[error, A] {
return E.TryCatchError(func() (A, error) {
var result A
err := json.Unmarshal(data, &result)
return result, err
})
}
// Marshal converts a data structure to json
func Marshal[A any](a A) E.Either[error, []byte] {
return E.TryCatchError(func() ([]byte, error) {
return json.Marshal(a)
})
}

27
json/json_test.go Normal file
View File

@@ -0,0 +1,27 @@
package json
import (
"fmt"
"testing"
E "github.com/ibm/fp-go/either"
F "github.com/ibm/fp-go/function"
"github.com/stretchr/testify/assert"
)
type Json map[string]any
func TestJsonMarshal(t *testing.T) {
resRight := Unmarshal[Json]([]byte("{\"a\": \"b\"}"))
assert.True(t, E.IsRight(resRight))
resLeft := Unmarshal[Json]([]byte("{\"a\""))
assert.True(t, E.IsLeft(resLeft))
res1 := F.Pipe1(
resRight,
E.Chain(Marshal[Json]),
)
fmt.Println(res1)
}

22
json/type.go Normal file
View File

@@ -0,0 +1,22 @@
package json
import (
E "github.com/ibm/fp-go/either"
F "github.com/ibm/fp-go/function"
O "github.com/ibm/fp-go/option"
)
func ToTypeE[A any](src any) E.Either[error, A] {
return F.Pipe2(
src,
Marshal[any],
E.Chain(Unmarshal[A]),
)
}
func ToTypeO[A any](src any) O.Option[A] {
return F.Pipe1(
ToTypeE[A](src),
E.ToOption[error, A](),
)
}

25
json/type_test.go Normal file
View File

@@ -0,0 +1,25 @@
package json
import (
"testing"
E "github.com/ibm/fp-go/either"
F "github.com/ibm/fp-go/function"
"github.com/stretchr/testify/assert"
)
type TestType struct {
A string `json:"a"`
B int `json:"b"`
}
func TestToType(t *testing.T) {
generic := map[string]any{"a": "value", "b": 1}
assert.True(t, E.IsRight(ToTypeE[TestType](generic)))
assert.True(t, E.IsRight(ToTypeE[TestType](&generic)))
assert.Equal(t, E.Right[error](&TestType{A: "value", B: 1}), ToTypeE[*TestType](&generic))
assert.Equal(t, E.Right[error](TestType{A: "value", B: 1}), F.Pipe1(ToTypeE[*TestType](&generic), E.Map[error](F.Deref[TestType])))
}

View File

@@ -9,8 +9,8 @@ import (
func TraverseArrayG[GA ~[]A, GB ~[]B, A, B any](f func(A) Option[B]) func(GA) Option[GB] {
return RA.Traverse[GA](
Of[GB],
MonadMap[GB, func(B) GB],
MonadAp[GB, B],
Map[GB, func(B) GB],
Ap[GB, B],
f,
)

View File

@@ -13,176 +13,176 @@ func optionize[R any](f func() (R, bool)) Option[R] {
// Optionize0 converts a function with 0 parameters returning a tuple of a return value R and a boolean into a function with 0 parameters returning an Option[R]
func Optionize0[F ~func() (R, bool), R any](f F) func() Option[R] {
return func() Option[R] {
return optionize(func() (R, bool) {
return f()
})
}
return func() Option[R] {
return optionize(func() (R, bool) {
return f()
})
}
}
// Unoptionize0 converts a function with 0 parameters returning a tuple of a return value R and a boolean into a function with 0 parameters returning an Option[R]
func Unoptionize0[F ~func() Option[R], R any](f F) func() (R, bool) {
return func() (R, bool) {
return Unwrap(f())
}
return func() (R, bool) {
return Unwrap(f())
}
}
// Optionize1 converts a function with 1 parameters returning a tuple of a return value R and a boolean into a function with 1 parameters returning an Option[R]
func Optionize1[F ~func(T0) (R, bool), T0, R any](f F) func(T0) Option[R] {
return func(t0 T0) Option[R] {
return optionize(func() (R, bool) {
return f(t0)
})
}
return func(t0 T0) Option[R] {
return optionize(func() (R, bool) {
return f(t0)
})
}
}
// Unoptionize1 converts a function with 1 parameters returning a tuple of a return value R and a boolean into a function with 1 parameters returning an Option[R]
func Unoptionize1[F ~func(T0) Option[R], T0, R any](f F) func(T0) (R, bool) {
return func(t0 T0) (R, bool) {
return Unwrap(f(t0))
}
return func(t0 T0) (R, bool) {
return Unwrap(f(t0))
}
}
// Optionize2 converts a function with 2 parameters returning a tuple of a return value R and a boolean into a function with 2 parameters returning an Option[R]
func Optionize2[F ~func(T0, T1) (R, bool), T0, T1, R any](f F) func(T0, T1) Option[R] {
return func(t0 T0, t1 T1) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1)
})
}
return func(t0 T0, t1 T1) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1)
})
}
}
// Unoptionize2 converts a function with 2 parameters returning a tuple of a return value R and a boolean into a function with 2 parameters returning an Option[R]
func Unoptionize2[F ~func(T0, T1) Option[R], T0, T1, R any](f F) func(T0, T1) (R, bool) {
return func(t0 T0, t1 T1) (R, bool) {
return Unwrap(f(t0, t1))
}
return func(t0 T0, t1 T1) (R, bool) {
return Unwrap(f(t0, t1))
}
}
// Optionize3 converts a function with 3 parameters returning a tuple of a return value R and a boolean into a function with 3 parameters returning an Option[R]
func Optionize3[F ~func(T0, T1, T2) (R, bool), T0, T1, T2, R any](f F) func(T0, T1, T2) Option[R] {
return func(t0 T0, t1 T1, t2 T2) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1, t2)
})
}
return func(t0 T0, t1 T1, t2 T2) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1, t2)
})
}
}
// Unoptionize3 converts a function with 3 parameters returning a tuple of a return value R and a boolean into a function with 3 parameters returning an Option[R]
func Unoptionize3[F ~func(T0, T1, T2) Option[R], T0, T1, T2, R any](f F) func(T0, T1, T2) (R, bool) {
return func(t0 T0, t1 T1, t2 T2) (R, bool) {
return Unwrap(f(t0, t1, t2))
}
return func(t0 T0, t1 T1, t2 T2) (R, bool) {
return Unwrap(f(t0, t1, t2))
}
}
// Optionize4 converts a function with 4 parameters returning a tuple of a return value R and a boolean into a function with 4 parameters returning an Option[R]
func Optionize4[F ~func(T0, T1, T2, T3) (R, bool), T0, T1, T2, T3, R any](f F) func(T0, T1, T2, T3) Option[R] {
return func(t0 T0, t1 T1, t2 T2, t3 T3) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1, t2, t3)
})
}
return func(t0 T0, t1 T1, t2 T2, t3 T3) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1, t2, t3)
})
}
}
// Unoptionize4 converts a function with 4 parameters returning a tuple of a return value R and a boolean into a function with 4 parameters returning an Option[R]
func Unoptionize4[F ~func(T0, T1, T2, T3) Option[R], T0, T1, T2, T3, R any](f F) func(T0, T1, T2, T3) (R, bool) {
return func(t0 T0, t1 T1, t2 T2, t3 T3) (R, bool) {
return Unwrap(f(t0, t1, t2, t3))
}
return func(t0 T0, t1 T1, t2 T2, t3 T3) (R, bool) {
return Unwrap(f(t0, t1, t2, t3))
}
}
// Optionize5 converts a function with 5 parameters returning a tuple of a return value R and a boolean into a function with 5 parameters returning an Option[R]
func Optionize5[F ~func(T0, T1, T2, T3, T4) (R, bool), T0, T1, T2, T3, T4, R any](f F) func(T0, T1, T2, T3, T4) Option[R] {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1, t2, t3, t4)
})
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1, t2, t3, t4)
})
}
}
// Unoptionize5 converts a function with 5 parameters returning a tuple of a return value R and a boolean into a function with 5 parameters returning an Option[R]
func Unoptionize5[F ~func(T0, T1, T2, T3, T4) Option[R], T0, T1, T2, T3, T4, R any](f F) func(T0, T1, T2, T3, T4) (R, bool) {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4) (R, bool) {
return Unwrap(f(t0, t1, t2, t3, t4))
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4) (R, bool) {
return Unwrap(f(t0, t1, t2, t3, t4))
}
}
// Optionize6 converts a function with 6 parameters returning a tuple of a return value R and a boolean into a function with 6 parameters returning an Option[R]
func Optionize6[F ~func(T0, T1, T2, T3, T4, T5) (R, bool), T0, T1, T2, T3, T4, T5, R any](f F) func(T0, T1, T2, T3, T4, T5) Option[R] {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1, t2, t3, t4, t5)
})
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1, t2, t3, t4, t5)
})
}
}
// Unoptionize6 converts a function with 6 parameters returning a tuple of a return value R and a boolean into a function with 6 parameters returning an Option[R]
func Unoptionize6[F ~func(T0, T1, T2, T3, T4, T5) Option[R], T0, T1, T2, T3, T4, T5, R any](f F) func(T0, T1, T2, T3, T4, T5) (R, bool) {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) (R, bool) {
return Unwrap(f(t0, t1, t2, t3, t4, t5))
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) (R, bool) {
return Unwrap(f(t0, t1, t2, t3, t4, t5))
}
}
// Optionize7 converts a function with 7 parameters returning a tuple of a return value R and a boolean into a function with 7 parameters returning an Option[R]
func Optionize7[F ~func(T0, T1, T2, T3, T4, T5, T6) (R, bool), T0, T1, T2, T3, T4, T5, T6, R any](f F) func(T0, T1, T2, T3, T4, T5, T6) Option[R] {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1, t2, t3, t4, t5, t6)
})
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1, t2, t3, t4, t5, t6)
})
}
}
// Unoptionize7 converts a function with 7 parameters returning a tuple of a return value R and a boolean into a function with 7 parameters returning an Option[R]
func Unoptionize7[F ~func(T0, T1, T2, T3, T4, T5, T6) Option[R], T0, T1, T2, T3, T4, T5, T6, R any](f F) func(T0, T1, T2, T3, T4, T5, T6) (R, bool) {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) (R, bool) {
return Unwrap(f(t0, t1, t2, t3, t4, t5, t6))
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) (R, bool) {
return Unwrap(f(t0, t1, t2, t3, t4, t5, t6))
}
}
// Optionize8 converts a function with 8 parameters returning a tuple of a return value R and a boolean into a function with 8 parameters returning an Option[R]
func Optionize8[F ~func(T0, T1, T2, T3, T4, T5, T6, T7) (R, bool), T0, T1, T2, T3, T4, T5, T6, T7, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7) Option[R] {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1, t2, t3, t4, t5, t6, t7)
})
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1, t2, t3, t4, t5, t6, t7)
})
}
}
// Unoptionize8 converts a function with 8 parameters returning a tuple of a return value R and a boolean into a function with 8 parameters returning an Option[R]
func Unoptionize8[F ~func(T0, T1, T2, T3, T4, T5, T6, T7) Option[R], T0, T1, T2, T3, T4, T5, T6, T7, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7) (R, bool) {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) (R, bool) {
return Unwrap(f(t0, t1, t2, t3, t4, t5, t6, t7))
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) (R, bool) {
return Unwrap(f(t0, t1, t2, t3, t4, t5, t6, t7))
}
}
// Optionize9 converts a function with 9 parameters returning a tuple of a return value R and a boolean into a function with 9 parameters returning an Option[R]
func Optionize9[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, bool), T0, T1, T2, T3, T4, T5, T6, T7, T8, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8) Option[R] {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1, t2, t3, t4, t5, t6, t7, t8)
})
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1, t2, t3, t4, t5, t6, t7, t8)
})
}
}
// Unoptionize9 converts a function with 9 parameters returning a tuple of a return value R and a boolean into a function with 9 parameters returning an Option[R]
func Unoptionize9[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8) Option[R], T0, T1, T2, T3, T4, T5, T6, T7, T8, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, bool) {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) (R, bool) {
return Unwrap(f(t0, t1, t2, t3, t4, t5, t6, t7, t8))
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) (R, bool) {
return Unwrap(f(t0, t1, t2, t3, t4, t5, t6, t7, t8))
}
}
// Optionize10 converts a function with 10 parameters returning a tuple of a return value R and a boolean into a function with 10 parameters returning an Option[R]
func Optionize10[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, bool), 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) Option[R] {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9)
})
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) Option[R] {
return optionize(func() (R, bool) {
return f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9)
})
}
}
// Unoptionize10 converts a function with 10 parameters returning a tuple of a return value R and a boolean into a function with 10 parameters returning an Option[R]
func Unoptionize10[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) Option[R], 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) (R, bool) {
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) (R, bool) {
return Unwrap(f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9))
}
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) (R, bool) {
return Unwrap(f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9))
}
}

View File

@@ -9,8 +9,8 @@ import (
func TraverseRecordG[GA ~map[K]A, GB ~map[K]B, K comparable, A, B any](f func(A) Option[B]) func(GA) Option[GB] {
return RR.Traverse[GA](
Of[GB],
MonadMap[GB, func(B) GB],
MonadAp[GB, B],
Map[GB, func(B) GB],
Ap[GB, B],
f,
)

87
retry/generic/retry.go Normal file
View File

@@ -0,0 +1,87 @@
package generic
import (
"time"
F "github.com/ibm/fp-go/function"
O "github.com/ibm/fp-go/option"
R "github.com/ibm/fp-go/retry"
)
// Apply policy and delay by its amount if it results in a R.
// Returns updated status.
// HKTSTATUS = HKT<R.RetryStatus>
func applyAndDelay[HKTSTATUS any](
monadOf func(R.RetryStatus) HKTSTATUS,
monadDelay func(time.Duration) func(HKTSTATUS) HKTSTATUS,
) func(policy R.RetryPolicy, status R.RetryStatus) HKTSTATUS {
return func(policy R.RetryPolicy, status R.RetryStatus) HKTSTATUS {
newStatus := R.ApplyPolicy(policy, status)
return F.Pipe1(
newStatus.PreviousDelay,
O.Fold(
F.Nullary2(F.Constant(newStatus), monadOf),
func(delay time.Duration) HKTSTATUS {
return monadDelay(delay)(monadOf(newStatus))
},
),
)
}
}
// Retry combinator for actions that don't raise exceptions, but
// signal in their type the outcome has failed. Examples are the
// `Option`, `Either` and `EitherT` monads.
//
// policy - refers to the retry policy
// action - converts a status into an operation to be executed
// check - checks if the result of the action needs to be retried
func Retrying[HKTA, HKTSTATUS, A any](
monadChain func(func(A) HKTA) func(HKTA) HKTA,
monadChainStatus func(func(R.RetryStatus) HKTA) func(HKTSTATUS) HKTA,
monadOf func(A) HKTA,
monadOfStatus func(R.RetryStatus) HKTSTATUS,
monadDelay func(time.Duration) func(HKTSTATUS) HKTSTATUS,
policy R.RetryPolicy,
action func(R.RetryStatus) HKTA,
check func(A) bool,
) HKTA {
// delay callback
applyDelay := applyAndDelay(monadOfStatus, monadDelay)
// function to check if we need to retry or not
checkForRetry := O.FromPredicate(check)
var f func(status R.RetryStatus) HKTA
// need some lazy init because we reference it in the chain
f = func(status R.RetryStatus) HKTA {
return F.Pipe2(
status,
action,
monadChain(func(a A) HKTA {
return F.Pipe3(
a,
checkForRetry,
O.Map(func(a A) HKTA {
return F.Pipe1(
applyDelay(policy, status),
monadChainStatus(func(status R.RetryStatus) HKTA {
return F.Pipe1(
status.PreviousDelay,
O.Fold(F.Constant(monadOf(a)), func(_ time.Duration) HKTA {
return f(status)
}),
)
}),
)
}),
O.GetOrElse(F.Constant(monadOf(a))),
)
}),
)
}
// seed
return f(R.DefaultRetryStatus)
}

108
retry/retry.go Normal file
View File

@@ -0,0 +1,108 @@
package Retry
import (
"math"
"time"
F "github.com/ibm/fp-go/function"
M "github.com/ibm/fp-go/monoid"
O "github.com/ibm/fp-go/option"
"github.com/ibm/fp-go/ord"
)
type RetryStatus struct {
// Iteration number, where `0` is the first try
IterNumber uint
// Delay incurred so far from retries
CumulativeDelay time.Duration
// Latest attempt's delay. Will always be `none` on first run.
PreviousDelay O.Option[time.Duration]
}
// RetryPolicy is a function that takes an `RetryStatus` and
// possibly returns a delay in milliseconds. Iteration numbers start
// at zero and increase by one on each retry. A //None// return value from
// the function implies we have reached the retry limit.
type RetryPolicy = func(RetryStatus) O.Option[time.Duration]
const emptyDuration = time.Duration(0)
var ordDuration = ord.FromStrictCompare[time.Duration]()
// 'RetryPolicy' is a 'Monoid'. You can collapse multiple strategies into one using 'concat'.
// The semantics of this combination are as follows:
//
// 1. If either policy returns 'None', the combined policy returns
// 'None'. This can be used to inhibit after a number of retries,
// for example.
//
// 2. If both policies return a delay, the larger delay will be used.
// This is quite natural when combining multiple policies to achieve a
// certain effect.
var Monoid = M.FunctionMonoid[RetryStatus](O.ApplicativeMonoid(M.MakeMonoid(
ord.MaxSemigroup(ordDuration).Concat, emptyDuration)))
// LimitRetries retries immediately, but only up to `i` times.
func LimitRetries(i uint) RetryPolicy {
pred := func(value uint) bool {
return value < i
}
empty := F.Constant1[uint](emptyDuration)
return func(status RetryStatus) O.Option[time.Duration] {
return F.Pipe2(
status.IterNumber,
O.FromPredicate(pred),
O.Map(empty),
)
}
}
// ConstantDelay delays with unlimited retries
func ConstantDelay(delay time.Duration) RetryPolicy {
return F.Constant1[RetryStatus](O.Of(delay))
}
// CapDelay sets a time-upperbound for any delays that may be directed by the
// given policy. This function does not terminate the retrying. The policy
// capDelay(maxDelay, exponentialBackoff(n))` will never stop retrying. It
// will reach a state where it retries forever with a delay of `maxDelay`
// between each one. To get termination you need to use one of the
// 'limitRetries' function variants.
func CapDelay(maxDelay time.Duration, policy RetryPolicy) RetryPolicy {
return F.Flow2(
policy,
O.Map(F.Bind1st(ord.Min(ordDuration), maxDelay)),
)
}
// ExponentialBackoff grows delay exponentially each iteration.
// Each delay will increase by a factor of two.
func ExponentialBackoff(delay time.Duration) RetryPolicy {
return func(status RetryStatus) O.Option[time.Duration] {
return O.Some(delay * time.Duration(math.Pow(2, float64(status.IterNumber))))
}
}
/**
* Initial, default retry status. Exported mostly to allow user code
* to test their handlers and retry policies.
*/
var DefaultRetryStatus = RetryStatus{
IterNumber: 0,
CumulativeDelay: 0,
PreviousDelay: O.None[time.Duration](),
}
var getOrElseDelay = O.GetOrElse(F.Constant(emptyDuration))
/**
* Apply policy on status to see what the decision would be.
*/
func ApplyPolicy(policy RetryPolicy, status RetryStatus) RetryStatus {
previousDelay := policy(status)
return RetryStatus{
IterNumber: status.IterNumber + 1,
CumulativeDelay: status.CumulativeDelay + getOrElseDelay(previousDelay),
PreviousDelay: previousDelay,
}
}

View File

@@ -3,7 +3,6 @@
// 2023-07-14 13:19:47.4331101 +0200 CEST m=+0.011802301
package tuple
import (
M "github.com/ibm/fp-go/monoid"
O "github.com/ibm/fp-go/ord"
@@ -11,520 +10,630 @@ import (
// Tuple1 is a struct that carries 1 independently typed values
type Tuple1[T1 any] struct {
F1 T1
F1 T1
}
// Tuple2 is a struct that carries 2 independently typed values
type Tuple2[T1, T2 any] struct {
F1 T1
F2 T2
F1 T1
F2 T2
}
// Tuple3 is a struct that carries 3 independently typed values
type Tuple3[T1, T2, T3 any] struct {
F1 T1
F2 T2
F3 T3
F1 T1
F2 T2
F3 T3
}
// Tuple4 is a struct that carries 4 independently typed values
type Tuple4[T1, T2, T3, T4 any] struct {
F1 T1
F2 T2
F3 T3
F4 T4
F1 T1
F2 T2
F3 T3
F4 T4
}
// Tuple5 is a struct that carries 5 independently typed values
type Tuple5[T1, T2, T3, T4, T5 any] struct {
F1 T1
F2 T2
F3 T3
F4 T4
F5 T5
F1 T1
F2 T2
F3 T3
F4 T4
F5 T5
}
// Tuple6 is a struct that carries 6 independently typed values
type Tuple6[T1, T2, T3, T4, T5, T6 any] struct {
F1 T1
F2 T2
F3 T3
F4 T4
F5 T5
F6 T6
F1 T1
F2 T2
F3 T3
F4 T4
F5 T5
F6 T6
}
// Tuple7 is a struct that carries 7 independently typed values
type Tuple7[T1, T2, T3, T4, T5, T6, T7 any] struct {
F1 T1
F2 T2
F3 T3
F4 T4
F5 T5
F6 T6
F7 T7
F1 T1
F2 T2
F3 T3
F4 T4
F5 T5
F6 T6
F7 T7
}
// Tuple8 is a struct that carries 8 independently typed values
type Tuple8[T1, T2, T3, T4, T5, T6, T7, T8 any] struct {
F1 T1
F2 T2
F3 T3
F4 T4
F5 T5
F6 T6
F7 T7
F8 T8
F1 T1
F2 T2
F3 T3
F4 T4
F5 T5
F6 T6
F7 T7
F8 T8
}
// Tuple9 is a struct that carries 9 independently typed values
type Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any] struct {
F1 T1
F2 T2
F3 T3
F4 T4
F5 T5
F6 T6
F7 T7
F8 T8
F9 T9
F1 T1
F2 T2
F3 T3
F4 T4
F5 T5
F6 T6
F7 T7
F8 T8
F9 T9
}
// Tuple10 is a struct that carries 10 independently typed values
type Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any] struct {
F1 T1
F2 T2
F3 T3
F4 T4
F5 T5
F6 T6
F7 T7
F8 T8
F9 T9
F10 T10
F1 T1
F2 T2
F3 T3
F4 T4
F5 T5
F6 T6
F7 T7
F8 T8
F9 T9
F10 T10
}
// MakeTuple1 is a function that converts its 1 parameters into a [Tuple1]
func MakeTuple1[T1 any](t1 T1) Tuple1[T1] {
return Tuple1[T1]{t1}
return Tuple1[T1]{t1}
}
// Tupled1 converts a function with 1 parameters returning into a function taking a Tuple1
// The inverse function is [Untupled1]
func Tupled1[F ~func(T1) R, T1, R any](f F) func(Tuple1[T1]) R {
return func(t Tuple1[T1]) R {
return f(t.F1)
}
return func(t Tuple1[T1]) R {
return f(t.F1)
}
}
// Untupled1 converts a function with a [Tuple1] parameter into a function with 1 parameters
// The inverse function is [Tupled1]
func Untupled1[F ~func(Tuple1[T1]) R, T1, R any](f F) func(T1) R {
return func(t1 T1) R {
return f(MakeTuple1(t1))
}
return func(t1 T1) R {
return f(MakeTuple1(t1))
}
}
// Monoid1 creates a [Monoid] for a [Tuple1] based on 1 monoids for the contained types
func Monoid1[T1 any](m1 M.Monoid[T1]) M.Monoid[Tuple1[T1]] {
return M.MakeMonoid(func(l, r Tuple1[T1]) Tuple1[T1]{
return MakeTuple1(m1.Concat(l.F1, r.F1))
}, MakeTuple1(m1.Empty()))
return M.MakeMonoid(func(l, r Tuple1[T1]) Tuple1[T1] {
return MakeTuple1(m1.Concat(l.F1, r.F1))
}, MakeTuple1(m1.Empty()))
}
// Ord1 creates n [Ord] for a [Tuple1] based on 1 [Ord]s for the contained types
func Ord1[T1 any](o1 O.Ord[T1]) O.Ord[Tuple1[T1]] {
return O.MakeOrd(func(l, r Tuple1[T1]) int {
if c:= o1.Compare(l.F1, r.F1); c != 0 {return c}
return 0
}, func(l, r Tuple1[T1]) bool {
return o1.Equals(l.F1, r.F1)
})
return O.MakeOrd(func(l, r Tuple1[T1]) int {
if c := o1.Compare(l.F1, r.F1); c != 0 {
return c
}
return 0
}, func(l, r Tuple1[T1]) bool {
return o1.Equals(l.F1, r.F1)
})
}
// MakeTuple2 is a function that converts its 2 parameters into a [Tuple2]
func MakeTuple2[T1, T2 any](t1 T1, t2 T2) Tuple2[T1, T2] {
return Tuple2[T1, T2]{t1, t2}
return Tuple2[T1, T2]{t1, t2}
}
// Tupled2 converts a function with 2 parameters returning into a function taking a Tuple2
// The inverse function is [Untupled2]
func Tupled2[F ~func(T1, T2) R, T1, T2, R any](f F) func(Tuple2[T1, T2]) R {
return func(t Tuple2[T1, T2]) R {
return f(t.F1, t.F2)
}
return func(t Tuple2[T1, T2]) R {
return f(t.F1, t.F2)
}
}
// Untupled2 converts a function with a [Tuple2] parameter into a function with 2 parameters
// The inverse function is [Tupled2]
func Untupled2[F ~func(Tuple2[T1, T2]) R, T1, T2, R any](f F) func(T1, T2) R {
return func(t1 T1, t2 T2) R {
return f(MakeTuple2(t1, t2))
}
return func(t1 T1, t2 T2) R {
return f(MakeTuple2(t1, t2))
}
}
// Monoid2 creates a [Monoid] for a [Tuple2] based on 2 monoids for the contained types
func Monoid2[T1, T2 any](m1 M.Monoid[T1], m2 M.Monoid[T2]) M.Monoid[Tuple2[T1, T2]] {
return M.MakeMonoid(func(l, r Tuple2[T1, T2]) Tuple2[T1, T2]{
return MakeTuple2(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2))
}, MakeTuple2(m1.Empty(), m2.Empty()))
return M.MakeMonoid(func(l, r Tuple2[T1, T2]) Tuple2[T1, T2] {
return MakeTuple2(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2))
}, MakeTuple2(m1.Empty(), m2.Empty()))
}
// Ord2 creates n [Ord] for a [Tuple2] based on 2 [Ord]s for the contained types
func Ord2[T1, T2 any](o1 O.Ord[T1], o2 O.Ord[T2]) O.Ord[Tuple2[T1, T2]] {
return O.MakeOrd(func(l, r Tuple2[T1, T2]) int {
if c:= o1.Compare(l.F1, r.F1); c != 0 {return c}
if c:= o2.Compare(l.F2, r.F2); c != 0 {return c}
return 0
}, func(l, r Tuple2[T1, T2]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2)
})
return O.MakeOrd(func(l, r Tuple2[T1, T2]) int {
if c := o1.Compare(l.F1, r.F1); c != 0 {
return c
}
if c := o2.Compare(l.F2, r.F2); c != 0 {
return c
}
return 0
}, func(l, r Tuple2[T1, T2]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2)
})
}
// MakeTuple3 is a function that converts its 3 parameters into a [Tuple3]
func MakeTuple3[T1, T2, T3 any](t1 T1, t2 T2, t3 T3) Tuple3[T1, T2, T3] {
return Tuple3[T1, T2, T3]{t1, t2, t3}
return Tuple3[T1, T2, T3]{t1, t2, t3}
}
// Tupled3 converts a function with 3 parameters returning into a function taking a Tuple3
// The inverse function is [Untupled3]
func Tupled3[F ~func(T1, T2, T3) R, T1, T2, T3, R any](f F) func(Tuple3[T1, T2, T3]) R {
return func(t Tuple3[T1, T2, T3]) R {
return f(t.F1, t.F2, t.F3)
}
return func(t Tuple3[T1, T2, T3]) R {
return f(t.F1, t.F2, t.F3)
}
}
// Untupled3 converts a function with a [Tuple3] parameter into a function with 3 parameters
// The inverse function is [Tupled3]
func Untupled3[F ~func(Tuple3[T1, T2, T3]) R, T1, T2, T3, R any](f F) func(T1, T2, T3) R {
return func(t1 T1, t2 T2, t3 T3) R {
return f(MakeTuple3(t1, t2, t3))
}
return func(t1 T1, t2 T2, t3 T3) R {
return f(MakeTuple3(t1, t2, t3))
}
}
// Monoid3 creates a [Monoid] for a [Tuple3] based on 3 monoids for the contained types
func Monoid3[T1, T2, T3 any](m1 M.Monoid[T1], m2 M.Monoid[T2], m3 M.Monoid[T3]) M.Monoid[Tuple3[T1, T2, T3]] {
return M.MakeMonoid(func(l, r Tuple3[T1, T2, T3]) Tuple3[T1, T2, T3]{
return MakeTuple3(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2), m3.Concat(l.F3, r.F3))
}, MakeTuple3(m1.Empty(), m2.Empty(), m3.Empty()))
return M.MakeMonoid(func(l, r Tuple3[T1, T2, T3]) Tuple3[T1, T2, T3] {
return MakeTuple3(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2), m3.Concat(l.F3, r.F3))
}, MakeTuple3(m1.Empty(), m2.Empty(), m3.Empty()))
}
// Ord3 creates n [Ord] for a [Tuple3] based on 3 [Ord]s for the contained types
func Ord3[T1, T2, T3 any](o1 O.Ord[T1], o2 O.Ord[T2], o3 O.Ord[T3]) O.Ord[Tuple3[T1, T2, T3]] {
return O.MakeOrd(func(l, r Tuple3[T1, T2, T3]) int {
if c:= o1.Compare(l.F1, r.F1); c != 0 {return c}
if c:= o2.Compare(l.F2, r.F2); c != 0 {return c}
if c:= o3.Compare(l.F3, r.F3); c != 0 {return c}
return 0
}, func(l, r Tuple3[T1, T2, T3]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2) && o3.Equals(l.F3, r.F3)
})
return O.MakeOrd(func(l, r Tuple3[T1, T2, T3]) int {
if c := o1.Compare(l.F1, r.F1); c != 0 {
return c
}
if c := o2.Compare(l.F2, r.F2); c != 0 {
return c
}
if c := o3.Compare(l.F3, r.F3); c != 0 {
return c
}
return 0
}, func(l, r Tuple3[T1, T2, T3]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2) && o3.Equals(l.F3, r.F3)
})
}
// MakeTuple4 is a function that converts its 4 parameters into a [Tuple4]
func MakeTuple4[T1, T2, T3, T4 any](t1 T1, t2 T2, t3 T3, t4 T4) Tuple4[T1, T2, T3, T4] {
return Tuple4[T1, T2, T3, T4]{t1, t2, t3, t4}
return Tuple4[T1, T2, T3, T4]{t1, t2, t3, t4}
}
// Tupled4 converts a function with 4 parameters returning into a function taking a Tuple4
// The inverse function is [Untupled4]
func Tupled4[F ~func(T1, T2, T3, T4) R, T1, T2, T3, T4, R any](f F) func(Tuple4[T1, T2, T3, T4]) R {
return func(t Tuple4[T1, T2, T3, T4]) R {
return f(t.F1, t.F2, t.F3, t.F4)
}
return func(t Tuple4[T1, T2, T3, T4]) R {
return f(t.F1, t.F2, t.F3, t.F4)
}
}
// Untupled4 converts a function with a [Tuple4] parameter into a function with 4 parameters
// The inverse function is [Tupled4]
func Untupled4[F ~func(Tuple4[T1, T2, T3, T4]) R, T1, T2, T3, T4, R any](f F) func(T1, T2, T3, T4) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(MakeTuple4(t1, t2, t3, t4))
}
return func(t1 T1, t2 T2, t3 T3, t4 T4) R {
return f(MakeTuple4(t1, t2, t3, t4))
}
}
// Monoid4 creates a [Monoid] for a [Tuple4] based on 4 monoids for the contained types
func Monoid4[T1, T2, T3, T4 any](m1 M.Monoid[T1], m2 M.Monoid[T2], m3 M.Monoid[T3], m4 M.Monoid[T4]) M.Monoid[Tuple4[T1, T2, T3, T4]] {
return M.MakeMonoid(func(l, r Tuple4[T1, T2, T3, T4]) Tuple4[T1, T2, T3, T4]{
return MakeTuple4(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2), m3.Concat(l.F3, r.F3), m4.Concat(l.F4, r.F4))
}, MakeTuple4(m1.Empty(), m2.Empty(), m3.Empty(), m4.Empty()))
return M.MakeMonoid(func(l, r Tuple4[T1, T2, T3, T4]) Tuple4[T1, T2, T3, T4] {
return MakeTuple4(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2), m3.Concat(l.F3, r.F3), m4.Concat(l.F4, r.F4))
}, MakeTuple4(m1.Empty(), m2.Empty(), m3.Empty(), m4.Empty()))
}
// Ord4 creates n [Ord] for a [Tuple4] based on 4 [Ord]s for the contained types
func Ord4[T1, T2, T3, T4 any](o1 O.Ord[T1], o2 O.Ord[T2], o3 O.Ord[T3], o4 O.Ord[T4]) O.Ord[Tuple4[T1, T2, T3, T4]] {
return O.MakeOrd(func(l, r Tuple4[T1, T2, T3, T4]) int {
if c:= o1.Compare(l.F1, r.F1); c != 0 {return c}
if c:= o2.Compare(l.F2, r.F2); c != 0 {return c}
if c:= o3.Compare(l.F3, r.F3); c != 0 {return c}
if c:= o4.Compare(l.F4, r.F4); c != 0 {return c}
return 0
}, func(l, r Tuple4[T1, T2, T3, T4]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2) && o3.Equals(l.F3, r.F3) && o4.Equals(l.F4, r.F4)
})
return O.MakeOrd(func(l, r Tuple4[T1, T2, T3, T4]) int {
if c := o1.Compare(l.F1, r.F1); c != 0 {
return c
}
if c := o2.Compare(l.F2, r.F2); c != 0 {
return c
}
if c := o3.Compare(l.F3, r.F3); c != 0 {
return c
}
if c := o4.Compare(l.F4, r.F4); c != 0 {
return c
}
return 0
}, func(l, r Tuple4[T1, T2, T3, T4]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2) && o3.Equals(l.F3, r.F3) && o4.Equals(l.F4, r.F4)
})
}
// MakeTuple5 is a function that converts its 5 parameters into a [Tuple5]
func MakeTuple5[T1, T2, T3, T4, T5 any](t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) Tuple5[T1, T2, T3, T4, T5] {
return Tuple5[T1, T2, T3, T4, T5]{t1, t2, t3, t4, t5}
return Tuple5[T1, T2, T3, T4, T5]{t1, t2, t3, t4, t5}
}
// Tupled5 converts a function with 5 parameters returning into a function taking a Tuple5
// The inverse function is [Untupled5]
func Tupled5[F ~func(T1, T2, T3, T4, T5) R, T1, T2, T3, T4, T5, R any](f F) func(Tuple5[T1, T2, T3, T4, T5]) R {
return func(t Tuple5[T1, T2, T3, T4, T5]) R {
return f(t.F1, t.F2, t.F3, t.F4, t.F5)
}
return func(t Tuple5[T1, T2, T3, T4, T5]) R {
return f(t.F1, t.F2, t.F3, t.F4, t.F5)
}
}
// Untupled5 converts a function with a [Tuple5] parameter into a function with 5 parameters
// The inverse function is [Tupled5]
func Untupled5[F ~func(Tuple5[T1, T2, T3, T4, T5]) R, T1, T2, T3, T4, T5, R any](f F) func(T1, T2, T3, T4, T5) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) R {
return f(MakeTuple5(t1, t2, t3, t4, t5))
}
return func(t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) R {
return f(MakeTuple5(t1, t2, t3, t4, t5))
}
}
// Monoid5 creates a [Monoid] for a [Tuple5] based on 5 monoids for the contained types
func Monoid5[T1, T2, T3, T4, T5 any](m1 M.Monoid[T1], m2 M.Monoid[T2], m3 M.Monoid[T3], m4 M.Monoid[T4], m5 M.Monoid[T5]) M.Monoid[Tuple5[T1, T2, T3, T4, T5]] {
return M.MakeMonoid(func(l, r Tuple5[T1, T2, T3, T4, T5]) Tuple5[T1, T2, T3, T4, T5]{
return MakeTuple5(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2), m3.Concat(l.F3, r.F3), m4.Concat(l.F4, r.F4), m5.Concat(l.F5, r.F5))
}, MakeTuple5(m1.Empty(), m2.Empty(), m3.Empty(), m4.Empty(), m5.Empty()))
return M.MakeMonoid(func(l, r Tuple5[T1, T2, T3, T4, T5]) Tuple5[T1, T2, T3, T4, T5] {
return MakeTuple5(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2), m3.Concat(l.F3, r.F3), m4.Concat(l.F4, r.F4), m5.Concat(l.F5, r.F5))
}, MakeTuple5(m1.Empty(), m2.Empty(), m3.Empty(), m4.Empty(), m5.Empty()))
}
// Ord5 creates n [Ord] for a [Tuple5] based on 5 [Ord]s for the contained types
func Ord5[T1, T2, T3, T4, T5 any](o1 O.Ord[T1], o2 O.Ord[T2], o3 O.Ord[T3], o4 O.Ord[T4], o5 O.Ord[T5]) O.Ord[Tuple5[T1, T2, T3, T4, T5]] {
return O.MakeOrd(func(l, r Tuple5[T1, T2, T3, T4, T5]) int {
if c:= o1.Compare(l.F1, r.F1); c != 0 {return c}
if c:= o2.Compare(l.F2, r.F2); c != 0 {return c}
if c:= o3.Compare(l.F3, r.F3); c != 0 {return c}
if c:= o4.Compare(l.F4, r.F4); c != 0 {return c}
if c:= o5.Compare(l.F5, r.F5); c != 0 {return c}
return 0
}, func(l, r Tuple5[T1, T2, T3, T4, T5]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2) && o3.Equals(l.F3, r.F3) && o4.Equals(l.F4, r.F4) && o5.Equals(l.F5, r.F5)
})
return O.MakeOrd(func(l, r Tuple5[T1, T2, T3, T4, T5]) int {
if c := o1.Compare(l.F1, r.F1); c != 0 {
return c
}
if c := o2.Compare(l.F2, r.F2); c != 0 {
return c
}
if c := o3.Compare(l.F3, r.F3); c != 0 {
return c
}
if c := o4.Compare(l.F4, r.F4); c != 0 {
return c
}
if c := o5.Compare(l.F5, r.F5); c != 0 {
return c
}
return 0
}, func(l, r Tuple5[T1, T2, T3, T4, T5]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2) && o3.Equals(l.F3, r.F3) && o4.Equals(l.F4, r.F4) && o5.Equals(l.F5, r.F5)
})
}
// MakeTuple6 is a function that converts its 6 parameters into a [Tuple6]
func MakeTuple6[T1, T2, T3, T4, T5, T6 any](t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) Tuple6[T1, T2, T3, T4, T5, T6] {
return Tuple6[T1, T2, T3, T4, T5, T6]{t1, t2, t3, t4, t5, t6}
return Tuple6[T1, T2, T3, T4, T5, T6]{t1, t2, t3, t4, t5, t6}
}
// Tupled6 converts a function with 6 parameters returning into a function taking a Tuple6
// The inverse function is [Untupled6]
func Tupled6[F ~func(T1, T2, T3, T4, T5, T6) R, T1, T2, T3, T4, T5, T6, R any](f F) func(Tuple6[T1, T2, T3, T4, T5, T6]) R {
return func(t Tuple6[T1, T2, T3, T4, T5, T6]) R {
return f(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6)
}
return func(t Tuple6[T1, T2, T3, T4, T5, T6]) R {
return f(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6)
}
}
// Untupled6 converts a function with a [Tuple6] parameter into a function with 6 parameters
// The inverse function is [Tupled6]
func Untupled6[F ~func(Tuple6[T1, T2, T3, T4, T5, T6]) R, T1, T2, T3, T4, T5, T6, R any](f F) func(T1, T2, T3, T4, T5, T6) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) R {
return f(MakeTuple6(t1, t2, t3, t4, t5, t6))
}
return func(t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) R {
return f(MakeTuple6(t1, t2, t3, t4, t5, t6))
}
}
// Monoid6 creates a [Monoid] for a [Tuple6] based on 6 monoids for the contained types
func Monoid6[T1, T2, T3, T4, T5, T6 any](m1 M.Monoid[T1], m2 M.Monoid[T2], m3 M.Monoid[T3], m4 M.Monoid[T4], m5 M.Monoid[T5], m6 M.Monoid[T6]) M.Monoid[Tuple6[T1, T2, T3, T4, T5, T6]] {
return M.MakeMonoid(func(l, r Tuple6[T1, T2, T3, T4, T5, T6]) Tuple6[T1, T2, T3, T4, T5, T6]{
return MakeTuple6(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2), m3.Concat(l.F3, r.F3), m4.Concat(l.F4, r.F4), m5.Concat(l.F5, r.F5), m6.Concat(l.F6, r.F6))
}, MakeTuple6(m1.Empty(), m2.Empty(), m3.Empty(), m4.Empty(), m5.Empty(), m6.Empty()))
return M.MakeMonoid(func(l, r Tuple6[T1, T2, T3, T4, T5, T6]) Tuple6[T1, T2, T3, T4, T5, T6] {
return MakeTuple6(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2), m3.Concat(l.F3, r.F3), m4.Concat(l.F4, r.F4), m5.Concat(l.F5, r.F5), m6.Concat(l.F6, r.F6))
}, MakeTuple6(m1.Empty(), m2.Empty(), m3.Empty(), m4.Empty(), m5.Empty(), m6.Empty()))
}
// Ord6 creates n [Ord] for a [Tuple6] based on 6 [Ord]s for the contained types
func Ord6[T1, T2, T3, T4, T5, T6 any](o1 O.Ord[T1], o2 O.Ord[T2], o3 O.Ord[T3], o4 O.Ord[T4], o5 O.Ord[T5], o6 O.Ord[T6]) O.Ord[Tuple6[T1, T2, T3, T4, T5, T6]] {
return O.MakeOrd(func(l, r Tuple6[T1, T2, T3, T4, T5, T6]) int {
if c:= o1.Compare(l.F1, r.F1); c != 0 {return c}
if c:= o2.Compare(l.F2, r.F2); c != 0 {return c}
if c:= o3.Compare(l.F3, r.F3); c != 0 {return c}
if c:= o4.Compare(l.F4, r.F4); c != 0 {return c}
if c:= o5.Compare(l.F5, r.F5); c != 0 {return c}
if c:= o6.Compare(l.F6, r.F6); c != 0 {return c}
return 0
}, func(l, r Tuple6[T1, T2, T3, T4, T5, T6]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2) && o3.Equals(l.F3, r.F3) && o4.Equals(l.F4, r.F4) && o5.Equals(l.F5, r.F5) && o6.Equals(l.F6, r.F6)
})
return O.MakeOrd(func(l, r Tuple6[T1, T2, T3, T4, T5, T6]) int {
if c := o1.Compare(l.F1, r.F1); c != 0 {
return c
}
if c := o2.Compare(l.F2, r.F2); c != 0 {
return c
}
if c := o3.Compare(l.F3, r.F3); c != 0 {
return c
}
if c := o4.Compare(l.F4, r.F4); c != 0 {
return c
}
if c := o5.Compare(l.F5, r.F5); c != 0 {
return c
}
if c := o6.Compare(l.F6, r.F6); c != 0 {
return c
}
return 0
}, func(l, r Tuple6[T1, T2, T3, T4, T5, T6]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2) && o3.Equals(l.F3, r.F3) && o4.Equals(l.F4, r.F4) && o5.Equals(l.F5, r.F5) && o6.Equals(l.F6, r.F6)
})
}
// MakeTuple7 is a function that converts its 7 parameters into a [Tuple7]
func MakeTuple7[T1, T2, T3, T4, T5, T6, T7 any](t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) Tuple7[T1, T2, T3, T4, T5, T6, T7] {
return Tuple7[T1, T2, T3, T4, T5, T6, T7]{t1, t2, t3, t4, t5, t6, t7}
return Tuple7[T1, T2, T3, T4, T5, T6, T7]{t1, t2, t3, t4, t5, t6, t7}
}
// Tupled7 converts a function with 7 parameters returning into a function taking a Tuple7
// The inverse function is [Untupled7]
func Tupled7[F ~func(T1, T2, T3, T4, T5, T6, T7) R, T1, T2, T3, T4, T5, T6, T7, R any](f F) func(Tuple7[T1, T2, T3, T4, T5, T6, T7]) R {
return func(t Tuple7[T1, T2, T3, T4, T5, T6, T7]) R {
return f(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7)
}
return func(t Tuple7[T1, T2, T3, T4, T5, T6, T7]) R {
return f(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7)
}
}
// Untupled7 converts a function with a [Tuple7] parameter into a function with 7 parameters
// The inverse function is [Tupled7]
func Untupled7[F ~func(Tuple7[T1, T2, T3, T4, T5, T6, T7]) R, T1, T2, T3, T4, T5, T6, T7, R any](f F) func(T1, T2, T3, T4, T5, T6, T7) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) R {
return f(MakeTuple7(t1, t2, t3, t4, t5, t6, t7))
}
return func(t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) R {
return f(MakeTuple7(t1, t2, t3, t4, t5, t6, t7))
}
}
// Monoid7 creates a [Monoid] for a [Tuple7] based on 7 monoids for the contained types
func Monoid7[T1, T2, T3, T4, T5, T6, T7 any](m1 M.Monoid[T1], m2 M.Monoid[T2], m3 M.Monoid[T3], m4 M.Monoid[T4], m5 M.Monoid[T5], m6 M.Monoid[T6], m7 M.Monoid[T7]) M.Monoid[Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return M.MakeMonoid(func(l, r Tuple7[T1, T2, T3, T4, T5, T6, T7]) Tuple7[T1, T2, T3, T4, T5, T6, T7]{
return MakeTuple7(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2), m3.Concat(l.F3, r.F3), m4.Concat(l.F4, r.F4), m5.Concat(l.F5, r.F5), m6.Concat(l.F6, r.F6), m7.Concat(l.F7, r.F7))
}, MakeTuple7(m1.Empty(), m2.Empty(), m3.Empty(), m4.Empty(), m5.Empty(), m6.Empty(), m7.Empty()))
return M.MakeMonoid(func(l, r Tuple7[T1, T2, T3, T4, T5, T6, T7]) Tuple7[T1, T2, T3, T4, T5, T6, T7] {
return MakeTuple7(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2), m3.Concat(l.F3, r.F3), m4.Concat(l.F4, r.F4), m5.Concat(l.F5, r.F5), m6.Concat(l.F6, r.F6), m7.Concat(l.F7, r.F7))
}, MakeTuple7(m1.Empty(), m2.Empty(), m3.Empty(), m4.Empty(), m5.Empty(), m6.Empty(), m7.Empty()))
}
// Ord7 creates n [Ord] for a [Tuple7] based on 7 [Ord]s for the contained types
func Ord7[T1, T2, T3, T4, T5, T6, T7 any](o1 O.Ord[T1], o2 O.Ord[T2], o3 O.Ord[T3], o4 O.Ord[T4], o5 O.Ord[T5], o6 O.Ord[T6], o7 O.Ord[T7]) O.Ord[Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return O.MakeOrd(func(l, r Tuple7[T1, T2, T3, T4, T5, T6, T7]) int {
if c:= o1.Compare(l.F1, r.F1); c != 0 {return c}
if c:= o2.Compare(l.F2, r.F2); c != 0 {return c}
if c:= o3.Compare(l.F3, r.F3); c != 0 {return c}
if c:= o4.Compare(l.F4, r.F4); c != 0 {return c}
if c:= o5.Compare(l.F5, r.F5); c != 0 {return c}
if c:= o6.Compare(l.F6, r.F6); c != 0 {return c}
if c:= o7.Compare(l.F7, r.F7); c != 0 {return c}
return 0
}, func(l, r Tuple7[T1, T2, T3, T4, T5, T6, T7]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2) && o3.Equals(l.F3, r.F3) && o4.Equals(l.F4, r.F4) && o5.Equals(l.F5, r.F5) && o6.Equals(l.F6, r.F6) && o7.Equals(l.F7, r.F7)
})
return O.MakeOrd(func(l, r Tuple7[T1, T2, T3, T4, T5, T6, T7]) int {
if c := o1.Compare(l.F1, r.F1); c != 0 {
return c
}
if c := o2.Compare(l.F2, r.F2); c != 0 {
return c
}
if c := o3.Compare(l.F3, r.F3); c != 0 {
return c
}
if c := o4.Compare(l.F4, r.F4); c != 0 {
return c
}
if c := o5.Compare(l.F5, r.F5); c != 0 {
return c
}
if c := o6.Compare(l.F6, r.F6); c != 0 {
return c
}
if c := o7.Compare(l.F7, r.F7); c != 0 {
return c
}
return 0
}, func(l, r Tuple7[T1, T2, T3, T4, T5, T6, T7]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2) && o3.Equals(l.F3, r.F3) && o4.Equals(l.F4, r.F4) && o5.Equals(l.F5, r.F5) && o6.Equals(l.F6, r.F6) && o7.Equals(l.F7, r.F7)
})
}
// MakeTuple8 is a function that converts its 8 parameters into a [Tuple8]
func MakeTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) Tuple8[T1, T2, T3, T4, T5, T6, T7, T8] {
return Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]{t1, t2, t3, t4, t5, t6, t7, t8}
return Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]{t1, t2, t3, t4, t5, t6, t7, t8}
}
// Tupled8 converts a function with 8 parameters returning into a function taking a Tuple8
// The inverse function is [Untupled8]
func Tupled8[F ~func(T1, T2, T3, T4, T5, T6, T7, T8) R, T1, T2, T3, T4, T5, T6, T7, T8, R any](f F) func(Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]) R {
return func(t Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]) R {
return f(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8)
}
return func(t Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]) R {
return f(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8)
}
}
// Untupled8 converts a function with a [Tuple8] parameter into a function with 8 parameters
// The inverse function is [Tupled8]
func Untupled8[F ~func(Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]) R, T1, T2, T3, T4, T5, T6, T7, T8, R any](f F) func(T1, T2, T3, T4, T5, T6, T7, T8) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) R {
return f(MakeTuple8(t1, t2, t3, t4, t5, t6, t7, t8))
}
return func(t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) R {
return f(MakeTuple8(t1, t2, t3, t4, t5, t6, t7, t8))
}
}
// Monoid8 creates a [Monoid] for a [Tuple8] based on 8 monoids for the contained types
func Monoid8[T1, T2, T3, T4, T5, T6, T7, T8 any](m1 M.Monoid[T1], m2 M.Monoid[T2], m3 M.Monoid[T3], m4 M.Monoid[T4], m5 M.Monoid[T5], m6 M.Monoid[T6], m7 M.Monoid[T7], m8 M.Monoid[T8]) M.Monoid[Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return M.MakeMonoid(func(l, r Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]) Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]{
return MakeTuple8(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2), m3.Concat(l.F3, r.F3), m4.Concat(l.F4, r.F4), m5.Concat(l.F5, r.F5), m6.Concat(l.F6, r.F6), m7.Concat(l.F7, r.F7), m8.Concat(l.F8, r.F8))
}, MakeTuple8(m1.Empty(), m2.Empty(), m3.Empty(), m4.Empty(), m5.Empty(), m6.Empty(), m7.Empty(), m8.Empty()))
return M.MakeMonoid(func(l, r Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]) Tuple8[T1, T2, T3, T4, T5, T6, T7, T8] {
return MakeTuple8(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2), m3.Concat(l.F3, r.F3), m4.Concat(l.F4, r.F4), m5.Concat(l.F5, r.F5), m6.Concat(l.F6, r.F6), m7.Concat(l.F7, r.F7), m8.Concat(l.F8, r.F8))
}, MakeTuple8(m1.Empty(), m2.Empty(), m3.Empty(), m4.Empty(), m5.Empty(), m6.Empty(), m7.Empty(), m8.Empty()))
}
// Ord8 creates n [Ord] for a [Tuple8] based on 8 [Ord]s for the contained types
func Ord8[T1, T2, T3, T4, T5, T6, T7, T8 any](o1 O.Ord[T1], o2 O.Ord[T2], o3 O.Ord[T3], o4 O.Ord[T4], o5 O.Ord[T5], o6 O.Ord[T6], o7 O.Ord[T7], o8 O.Ord[T8]) O.Ord[Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return O.MakeOrd(func(l, r Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]) int {
if c:= o1.Compare(l.F1, r.F1); c != 0 {return c}
if c:= o2.Compare(l.F2, r.F2); c != 0 {return c}
if c:= o3.Compare(l.F3, r.F3); c != 0 {return c}
if c:= o4.Compare(l.F4, r.F4); c != 0 {return c}
if c:= o5.Compare(l.F5, r.F5); c != 0 {return c}
if c:= o6.Compare(l.F6, r.F6); c != 0 {return c}
if c:= o7.Compare(l.F7, r.F7); c != 0 {return c}
if c:= o8.Compare(l.F8, r.F8); c != 0 {return c}
return 0
}, func(l, r Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2) && o3.Equals(l.F3, r.F3) && o4.Equals(l.F4, r.F4) && o5.Equals(l.F5, r.F5) && o6.Equals(l.F6, r.F6) && o7.Equals(l.F7, r.F7) && o8.Equals(l.F8, r.F8)
})
return O.MakeOrd(func(l, r Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]) int {
if c := o1.Compare(l.F1, r.F1); c != 0 {
return c
}
if c := o2.Compare(l.F2, r.F2); c != 0 {
return c
}
if c := o3.Compare(l.F3, r.F3); c != 0 {
return c
}
if c := o4.Compare(l.F4, r.F4); c != 0 {
return c
}
if c := o5.Compare(l.F5, r.F5); c != 0 {
return c
}
if c := o6.Compare(l.F6, r.F6); c != 0 {
return c
}
if c := o7.Compare(l.F7, r.F7); c != 0 {
return c
}
if c := o8.Compare(l.F8, r.F8); c != 0 {
return c
}
return 0
}, func(l, r Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2) && o3.Equals(l.F3, r.F3) && o4.Equals(l.F4, r.F4) && o5.Equals(l.F5, r.F5) && o6.Equals(l.F6, r.F6) && o7.Equals(l.F7, r.F7) && o8.Equals(l.F8, r.F8)
})
}
// MakeTuple9 is a function that converts its 9 parameters into a [Tuple9]
func MakeTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9] {
return Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]{t1, t2, t3, t4, t5, t6, t7, t8, t9}
return Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]{t1, t2, t3, t4, t5, t6, t7, t8, t9}
}
// Tupled9 converts a function with 9 parameters returning into a function taking a Tuple9
// The inverse function is [Untupled9]
func Tupled9[F ~func(T1, T2, T3, T4, T5, T6, T7, T8, T9) R, T1, T2, T3, T4, T5, T6, T7, T8, T9, R any](f F) func(Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]) R {
return func(t Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]) R {
return f(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9)
}
return func(t Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]) R {
return f(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9)
}
}
// Untupled9 converts a function with a [Tuple9] parameter into a function with 9 parameters
// The inverse function is [Tupled9]
func Untupled9[F ~func(Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]) R, T1, T2, T3, T4, T5, T6, T7, T8, T9, R any](f F) func(T1, T2, T3, T4, T5, T6, T7, T8, T9) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) R {
return f(MakeTuple9(t1, t2, t3, t4, t5, t6, t7, t8, t9))
}
return func(t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) R {
return f(MakeTuple9(t1, t2, t3, t4, t5, t6, t7, t8, t9))
}
}
// Monoid9 creates a [Monoid] for a [Tuple9] based on 9 monoids for the contained types
func Monoid9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](m1 M.Monoid[T1], m2 M.Monoid[T2], m3 M.Monoid[T3], m4 M.Monoid[T4], m5 M.Monoid[T5], m6 M.Monoid[T6], m7 M.Monoid[T7], m8 M.Monoid[T8], m9 M.Monoid[T9]) M.Monoid[Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return M.MakeMonoid(func(l, r Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]) Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]{
return MakeTuple9(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2), m3.Concat(l.F3, r.F3), m4.Concat(l.F4, r.F4), m5.Concat(l.F5, r.F5), m6.Concat(l.F6, r.F6), m7.Concat(l.F7, r.F7), m8.Concat(l.F8, r.F8), m9.Concat(l.F9, r.F9))
}, MakeTuple9(m1.Empty(), m2.Empty(), m3.Empty(), m4.Empty(), m5.Empty(), m6.Empty(), m7.Empty(), m8.Empty(), m9.Empty()))
return M.MakeMonoid(func(l, r Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]) Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9] {
return MakeTuple9(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2), m3.Concat(l.F3, r.F3), m4.Concat(l.F4, r.F4), m5.Concat(l.F5, r.F5), m6.Concat(l.F6, r.F6), m7.Concat(l.F7, r.F7), m8.Concat(l.F8, r.F8), m9.Concat(l.F9, r.F9))
}, MakeTuple9(m1.Empty(), m2.Empty(), m3.Empty(), m4.Empty(), m5.Empty(), m6.Empty(), m7.Empty(), m8.Empty(), m9.Empty()))
}
// Ord9 creates n [Ord] for a [Tuple9] based on 9 [Ord]s for the contained types
func Ord9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](o1 O.Ord[T1], o2 O.Ord[T2], o3 O.Ord[T3], o4 O.Ord[T4], o5 O.Ord[T5], o6 O.Ord[T6], o7 O.Ord[T7], o8 O.Ord[T8], o9 O.Ord[T9]) O.Ord[Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return O.MakeOrd(func(l, r Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]) int {
if c:= o1.Compare(l.F1, r.F1); c != 0 {return c}
if c:= o2.Compare(l.F2, r.F2); c != 0 {return c}
if c:= o3.Compare(l.F3, r.F3); c != 0 {return c}
if c:= o4.Compare(l.F4, r.F4); c != 0 {return c}
if c:= o5.Compare(l.F5, r.F5); c != 0 {return c}
if c:= o6.Compare(l.F6, r.F6); c != 0 {return c}
if c:= o7.Compare(l.F7, r.F7); c != 0 {return c}
if c:= o8.Compare(l.F8, r.F8); c != 0 {return c}
if c:= o9.Compare(l.F9, r.F9); c != 0 {return c}
return 0
}, func(l, r Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2) && o3.Equals(l.F3, r.F3) && o4.Equals(l.F4, r.F4) && o5.Equals(l.F5, r.F5) && o6.Equals(l.F6, r.F6) && o7.Equals(l.F7, r.F7) && o8.Equals(l.F8, r.F8) && o9.Equals(l.F9, r.F9)
})
return O.MakeOrd(func(l, r Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]) int {
if c := o1.Compare(l.F1, r.F1); c != 0 {
return c
}
if c := o2.Compare(l.F2, r.F2); c != 0 {
return c
}
if c := o3.Compare(l.F3, r.F3); c != 0 {
return c
}
if c := o4.Compare(l.F4, r.F4); c != 0 {
return c
}
if c := o5.Compare(l.F5, r.F5); c != 0 {
return c
}
if c := o6.Compare(l.F6, r.F6); c != 0 {
return c
}
if c := o7.Compare(l.F7, r.F7); c != 0 {
return c
}
if c := o8.Compare(l.F8, r.F8); c != 0 {
return c
}
if c := o9.Compare(l.F9, r.F9); c != 0 {
return c
}
return 0
}, func(l, r Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2) && o3.Equals(l.F3, r.F3) && o4.Equals(l.F4, r.F4) && o5.Equals(l.F5, r.F5) && o6.Equals(l.F6, r.F6) && o7.Equals(l.F7, r.F7) && o8.Equals(l.F8, r.F8) && o9.Equals(l.F9, r.F9)
})
}
// MakeTuple10 is a function that converts its 10 parameters into a [Tuple10]
func MakeTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10) Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10] {
return Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10}
return Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10}
}
// Tupled10 converts a function with 10 parameters returning into a function taking a Tuple10
// The inverse function is [Untupled10]
func Tupled10[F ~func(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) R, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R any](f F) func(Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]) R {
return func(t Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]) R {
return f(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9, t.F10)
}
return func(t Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]) R {
return f(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9, t.F10)
}
}
// Untupled10 converts a function with a [Tuple10] parameter into a function with 10 parameters
// The inverse function is [Tupled10]
func Untupled10[F ~func(Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]) R, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R any](f F) func(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) R {
return func(t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10) R {
return f(MakeTuple10(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10))
}
return func(t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10) R {
return f(MakeTuple10(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10))
}
}
// Monoid10 creates a [Monoid] for a [Tuple10] based on 10 monoids for the contained types
func Monoid10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](m1 M.Monoid[T1], m2 M.Monoid[T2], m3 M.Monoid[T3], m4 M.Monoid[T4], m5 M.Monoid[T5], m6 M.Monoid[T6], m7 M.Monoid[T7], m8 M.Monoid[T8], m9 M.Monoid[T9], m10 M.Monoid[T10]) M.Monoid[Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return M.MakeMonoid(func(l, r Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]) Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]{
return MakeTuple10(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2), m3.Concat(l.F3, r.F3), m4.Concat(l.F4, r.F4), m5.Concat(l.F5, r.F5), m6.Concat(l.F6, r.F6), m7.Concat(l.F7, r.F7), m8.Concat(l.F8, r.F8), m9.Concat(l.F9, r.F9), m10.Concat(l.F10, r.F10))
}, MakeTuple10(m1.Empty(), m2.Empty(), m3.Empty(), m4.Empty(), m5.Empty(), m6.Empty(), m7.Empty(), m8.Empty(), m9.Empty(), m10.Empty()))
return M.MakeMonoid(func(l, r Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]) Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10] {
return MakeTuple10(m1.Concat(l.F1, r.F1), m2.Concat(l.F2, r.F2), m3.Concat(l.F3, r.F3), m4.Concat(l.F4, r.F4), m5.Concat(l.F5, r.F5), m6.Concat(l.F6, r.F6), m7.Concat(l.F7, r.F7), m8.Concat(l.F8, r.F8), m9.Concat(l.F9, r.F9), m10.Concat(l.F10, r.F10))
}, MakeTuple10(m1.Empty(), m2.Empty(), m3.Empty(), m4.Empty(), m5.Empty(), m6.Empty(), m7.Empty(), m8.Empty(), m9.Empty(), m10.Empty()))
}
// Ord10 creates n [Ord] for a [Tuple10] based on 10 [Ord]s for the contained types
func Ord10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](o1 O.Ord[T1], o2 O.Ord[T2], o3 O.Ord[T3], o4 O.Ord[T4], o5 O.Ord[T5], o6 O.Ord[T6], o7 O.Ord[T7], o8 O.Ord[T8], o9 O.Ord[T9], o10 O.Ord[T10]) O.Ord[Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return O.MakeOrd(func(l, r Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]) int {
if c:= o1.Compare(l.F1, r.F1); c != 0 {return c}
if c:= o2.Compare(l.F2, r.F2); c != 0 {return c}
if c:= o3.Compare(l.F3, r.F3); c != 0 {return c}
if c:= o4.Compare(l.F4, r.F4); c != 0 {return c}
if c:= o5.Compare(l.F5, r.F5); c != 0 {return c}
if c:= o6.Compare(l.F6, r.F6); c != 0 {return c}
if c:= o7.Compare(l.F7, r.F7); c != 0 {return c}
if c:= o8.Compare(l.F8, r.F8); c != 0 {return c}
if c:= o9.Compare(l.F9, r.F9); c != 0 {return c}
if c:= o10.Compare(l.F10, r.F10); c != 0 {return c}
return 0
}, func(l, r Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2) && o3.Equals(l.F3, r.F3) && o4.Equals(l.F4, r.F4) && o5.Equals(l.F5, r.F5) && o6.Equals(l.F6, r.F6) && o7.Equals(l.F7, r.F7) && o8.Equals(l.F8, r.F8) && o9.Equals(l.F9, r.F9) && o10.Equals(l.F10, r.F10)
})
return O.MakeOrd(func(l, r Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]) int {
if c := o1.Compare(l.F1, r.F1); c != 0 {
return c
}
if c := o2.Compare(l.F2, r.F2); c != 0 {
return c
}
if c := o3.Compare(l.F3, r.F3); c != 0 {
return c
}
if c := o4.Compare(l.F4, r.F4); c != 0 {
return c
}
if c := o5.Compare(l.F5, r.F5); c != 0 {
return c
}
if c := o6.Compare(l.F6, r.F6); c != 0 {
return c
}
if c := o7.Compare(l.F7, r.F7); c != 0 {
return c
}
if c := o8.Compare(l.F8, r.F8); c != 0 {
return c
}
if c := o9.Compare(l.F9, r.F9); c != 0 {
return c
}
if c := o10.Compare(l.F10, r.F10); c != 0 {
return c
}
return 0
}, func(l, r Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]) bool {
return o1.Equals(l.F1, r.F1) && o2.Equals(l.F2, r.F2) && o3.Equals(l.F3, r.F3) && o4.Equals(l.F4, r.F4) && o5.Equals(l.F5, r.F5) && o6.Equals(l.F6, r.F6) && o7.Equals(l.F7, r.F7) && o8.Equals(l.F8, r.F8) && o9.Equals(l.F9, r.F9) && o10.Equals(l.F10, r.F10)
})
}