mirror of
https://github.com/IBM/fp-go.git
synced 2025-06-23 00:27:49 +02:00
fix: add support for context sensitive readers
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
@ -45,7 +45,7 @@ func monadGenerateSequenceTNonGeneric(
|
||||
}
|
||||
fmt.Fprintf(f, ") %s {", hkt(tuple))
|
||||
// the actual apply callback
|
||||
fmt.Fprintf(f, " return Apply.SequenceT%d(\n", i)
|
||||
fmt.Fprintf(f, " return apply.SequenceT%d(\n", i)
|
||||
// map callback
|
||||
|
||||
curried := func(count int) string {
|
||||
@ -98,7 +98,7 @@ func monadGenerateSequenceTGeneric(
|
||||
}
|
||||
fmt.Fprintf(f, ") %s {", hkt(tuple))
|
||||
// the actual apply callback
|
||||
fmt.Fprintf(f, " return Apply.SequenceT%d(\n", i)
|
||||
fmt.Fprintf(f, " return apply.SequenceT%d(\n", i)
|
||||
// map callback
|
||||
|
||||
curried := func(count int) string {
|
||||
|
18
context/ioeither/ioeither.go
Normal file
18
context/ioeither/ioeither.go
Normal file
@ -0,0 +1,18 @@
|
||||
package ioeither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
IOE "github.com/ibm/fp-go/ioeither"
|
||||
)
|
||||
|
||||
// withContext wraps an existing IOEither and performs a context check for cancellation before delegating
|
||||
func WithContext[A any](ctx context.Context, ma IOE.IOEither[error, A]) IOE.IOEither[error, A] {
|
||||
return IOE.MakeIO(func() ET.Either[error, A] {
|
||||
if err := context.Cause(ctx); err != nil {
|
||||
return ET.Left[A](err)
|
||||
}
|
||||
return ma()
|
||||
})
|
||||
}
|
15
context/reader/array.go
Normal file
15
context/reader/array.go
Normal file
@ -0,0 +1,15 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
R "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func TraverseArray[A, B any](f func(A) Reader[B]) func([]A) Reader[[]B] {
|
||||
return R.TraverseArray[Reader[B], Reader[[]B], []A](f)
|
||||
}
|
||||
|
||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArray[A any](ma []Reader[A]) Reader[[]A] {
|
||||
return R.SequenceArray[Reader[A], Reader[[]A]](ma)
|
||||
}
|
38
context/reader/curry.go
Normal file
38
context/reader/curry.go
Normal file
@ -0,0 +1,38 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func Curry0[A any](f func(context.Context) A) Reader[A] {
|
||||
return R.Curry0[Reader[A]](f)
|
||||
}
|
||||
|
||||
func Curry1[T1, A any](f func(context.Context, T1) A) func(T1) Reader[A] {
|
||||
return R.Curry1[Reader[A]](f)
|
||||
}
|
||||
|
||||
func Curry2[T1, T2, A any](f func(context.Context, T1, T2) A) func(T1) func(T2) Reader[A] {
|
||||
return R.Curry2[Reader[A]](f)
|
||||
}
|
||||
|
||||
func Curry3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) A) func(T1) func(T2) func(T3) Reader[A] {
|
||||
return R.Curry3[Reader[A]](f)
|
||||
}
|
||||
|
||||
func Uncurry1[T1, A any](f func(T1) Reader[A]) func(context.Context, T1) A {
|
||||
return R.Uncurry1(f)
|
||||
}
|
||||
|
||||
func Uncurry2[T1, T2, A any](f func(T1) func(T2) Reader[A]) func(context.Context, T1, T2) A {
|
||||
return R.Uncurry2(f)
|
||||
}
|
||||
|
||||
func Uncurry3[T1, T2, T3, A any](f func(T1) func(T2) func(T3) Reader[A]) func(context.Context, T1, T2, T3) A {
|
||||
return R.Uncurry3(f)
|
||||
}
|
26
context/reader/from.go
Normal file
26
context/reader/from.go
Normal file
@ -0,0 +1,26 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func From0[A any](f func(context.Context) A) Reader[A] {
|
||||
return R.From0[Reader[A]](f)
|
||||
}
|
||||
|
||||
func From1[T1, A any](f func(context.Context, T1) A) func(T1) Reader[A] {
|
||||
return R.From1[Reader[A]](f)
|
||||
}
|
||||
|
||||
func From2[T1, T2, A any](f func(context.Context, T1, T2) A) func(T1, T2) Reader[A] {
|
||||
return R.From2[Reader[A]](f)
|
||||
}
|
||||
|
||||
func From3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) A) func(T1, T2, T3) Reader[A] {
|
||||
return R.From3[Reader[A]](f)
|
||||
}
|
43
context/reader/reader.go
Normal file
43
context/reader/reader.go
Normal file
@ -0,0 +1,43 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
func MonadMap[A, B any](fa Reader[A], f func(A) B) Reader[B] {
|
||||
return R.MonadMap[Reader[A], Reader[B]](fa, f)
|
||||
}
|
||||
|
||||
func Map[A, B any](f func(A) B) func(Reader[A]) Reader[B] {
|
||||
return R.Map[Reader[A], Reader[B]](f)
|
||||
}
|
||||
|
||||
func MonadChain[A, B any](ma Reader[A], f func(A) Reader[B]) Reader[B] {
|
||||
return R.MonadChain(ma, f)
|
||||
}
|
||||
|
||||
func Chain[A, B any](f func(A) Reader[B]) func(Reader[A]) Reader[B] {
|
||||
return R.Chain[Reader[A]](f)
|
||||
}
|
||||
|
||||
func Of[A any](a A) Reader[A] {
|
||||
return R.Of[Reader[A]](a)
|
||||
}
|
||||
|
||||
func MonadAp[A, B any](fab Reader[func(A) B], fa Reader[A]) Reader[B] {
|
||||
return R.MonadAp[Reader[A], Reader[B]](fab, fa)
|
||||
}
|
||||
|
||||
func Ap[A, B any](fa Reader[A]) func(Reader[func(A) B]) Reader[B] {
|
||||
return R.Ap[Reader[A], Reader[B], Reader[func(A) B]](fa)
|
||||
}
|
||||
|
||||
func Ask() Reader[context.Context] {
|
||||
return R.Ask[Reader[context.Context]]()
|
||||
}
|
||||
|
||||
func Asks[A any](r Reader[A]) Reader[A] {
|
||||
return R.Asks(r)
|
||||
}
|
60
context/reader/reader_test.go
Normal file
60
context/reader/reader_test.go
Normal file
@ -0,0 +1,60 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
F "github.com/ibm/fp-go/function"
|
||||
T "github.com/ibm/fp-go/tuple"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func GoFunction(ctx context.Context, data string) string {
|
||||
return strings.ToUpper(data)
|
||||
}
|
||||
|
||||
func GoIntFunction(ctx context.Context, data string, number int) string {
|
||||
return fmt.Sprintf("%s: %d", data, number)
|
||||
}
|
||||
|
||||
func TestReaderFrom(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
f := From1(GoFunction)
|
||||
|
||||
result := f("input")(ctx)
|
||||
|
||||
assert.Equal(t, result, "INPUT")
|
||||
|
||||
}
|
||||
|
||||
func MyFinalResult(left, right string) string {
|
||||
return fmt.Sprintf("%s-%s", left, right)
|
||||
}
|
||||
|
||||
func TestReadersFrom(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
f1 := From1(GoFunction)
|
||||
f2 := From2(GoIntFunction)
|
||||
|
||||
result1 := f1("input")(ctx)
|
||||
result2 := f2("input", 10)(ctx)
|
||||
|
||||
result3 := MyFinalResult(result1, result2)
|
||||
|
||||
h := F.Pipe1(
|
||||
SequenceT2(f1("input"), f2("input", 10)),
|
||||
Map(T.Tupled2(MyFinalResult)),
|
||||
)
|
||||
|
||||
composedResult := h(ctx)
|
||||
|
||||
assert.Equal(t, result1, "INPUT")
|
||||
assert.Equal(t, result2, "input: 10")
|
||||
assert.Equal(t, result3, "INPUT-input: 10")
|
||||
|
||||
assert.Equal(t, composedResult, "INPUT-input: 10")
|
||||
|
||||
}
|
42
context/reader/sequence.go
Normal file
42
context/reader/sequence.go
Normal file
@ -0,0 +1,42 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
R "github.com/ibm/fp-go/reader/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 Reader[A]) Reader[T.Tuple1[A]] {
|
||||
return R.SequenceT1[
|
||||
Reader[A],
|
||||
Reader[T.Tuple1[A]],
|
||||
](a)
|
||||
}
|
||||
|
||||
func SequenceT2[A, B any](a Reader[A], b Reader[B]) Reader[T.Tuple2[A, B]] {
|
||||
return R.SequenceT2[
|
||||
Reader[A],
|
||||
Reader[B],
|
||||
Reader[T.Tuple2[A, B]],
|
||||
](a, b)
|
||||
}
|
||||
|
||||
func SequenceT3[A, B, C any](a Reader[A], b Reader[B], c Reader[C]) Reader[T.Tuple3[A, B, C]] {
|
||||
return R.SequenceT3[
|
||||
Reader[A],
|
||||
Reader[B],
|
||||
Reader[C],
|
||||
Reader[T.Tuple3[A, B, C]],
|
||||
](a, b, c)
|
||||
}
|
||||
|
||||
func SequenceT4[A, B, C, D any](a Reader[A], b Reader[B], c Reader[C], d Reader[D]) Reader[T.Tuple4[A, B, C, D]] {
|
||||
return R.SequenceT4[
|
||||
Reader[A],
|
||||
Reader[B],
|
||||
Reader[C],
|
||||
Reader[D],
|
||||
Reader[T.Tuple4[A, B, C, D]],
|
||||
](a, b, c, d)
|
||||
}
|
11
context/reader/type.go
Normal file
11
context/reader/type.go
Normal file
@ -0,0 +1,11 @@
|
||||
// Package reader implements a specialization of the Reader monad assuming a golang context as the context of the monad
|
||||
package reader
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/ibm/fp-go/reader"
|
||||
)
|
||||
|
||||
// Reader is a specialization of the Reader monad assuming a golang context as the context of the monad
|
||||
type Reader[A any] R.Reader[context.Context, A]
|
15
context/readereither/array.go
Normal file
15
context/readereither/array.go
Normal file
@ -0,0 +1,15 @@
|
||||
package readereither
|
||||
|
||||
import (
|
||||
RE "github.com/ibm/fp-go/readereither/generic"
|
||||
)
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func TraverseArray[A, B any](f func(A) ReaderEither[B]) func([]A) ReaderEither[[]B] {
|
||||
return RE.TraverseArray[ReaderEither[B], ReaderEither[[]B], []A](f)
|
||||
}
|
||||
|
||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArray[A any](ma []ReaderEither[A]) ReaderEither[[]A] {
|
||||
return RE.SequenceArray[ReaderEither[A], ReaderEither[[]A]](ma)
|
||||
}
|
17
context/readereither/cancel.go
Normal file
17
context/readereither/cancel.go
Normal file
@ -0,0 +1,17 @@
|
||||
package readereither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
E "github.com/ibm/fp-go/either"
|
||||
)
|
||||
|
||||
// withContext wraps an existing ReaderEither and performs a context check for cancellation before deletating
|
||||
func WithContext[A any](ma ReaderEither[A]) ReaderEither[A] {
|
||||
return func(ctx context.Context) E.Either[error, A] {
|
||||
if err := context.Cause(ctx); err != nil {
|
||||
return E.Left[A](err)
|
||||
}
|
||||
return ma(ctx)
|
||||
}
|
||||
}
|
38
context/readereither/curry.go
Normal file
38
context/readereither/curry.go
Normal file
@ -0,0 +1,38 @@
|
||||
package readereither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
RE "github.com/ibm/fp-go/readereither/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func Curry0[A any](f func(context.Context) (A, error)) ReaderEither[A] {
|
||||
return RE.Curry0[ReaderEither[A]](f)
|
||||
}
|
||||
|
||||
func Curry1[T1, A any](f func(context.Context, T1) (A, error)) func(T1) ReaderEither[A] {
|
||||
return RE.Curry1[ReaderEither[A]](f)
|
||||
}
|
||||
|
||||
func Curry2[T1, T2, A any](f func(context.Context, T1, T2) (A, error)) func(T1) func(T2) ReaderEither[A] {
|
||||
return RE.Curry2[ReaderEither[A]](f)
|
||||
}
|
||||
|
||||
func Curry3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) (A, error)) func(T1) func(T2) func(T3) ReaderEither[A] {
|
||||
return RE.Curry3[ReaderEither[A]](f)
|
||||
}
|
||||
|
||||
func Uncurry1[T1, A any](f func(T1) ReaderEither[A]) func(context.Context, T1) (A, error) {
|
||||
return RE.Uncurry1(f)
|
||||
}
|
||||
|
||||
func Uncurry2[T1, T2, A any](f func(T1) func(T2) ReaderEither[A]) func(context.Context, T1, T2) (A, error) {
|
||||
return RE.Uncurry2(f)
|
||||
}
|
||||
|
||||
func Uncurry3[T1, T2, T3, A any](f func(T1) func(T2) func(T3) ReaderEither[A]) func(context.Context, T1, T2, T3) (A, error) {
|
||||
return RE.Uncurry3(f)
|
||||
}
|
26
context/readereither/exec/exec.go
Normal file
26
context/readereither/exec/exec.go
Normal file
@ -0,0 +1,26 @@
|
||||
package exec
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
RE "github.com/ibm/fp-go/context/readereither"
|
||||
E "github.com/ibm/fp-go/either"
|
||||
"github.com/ibm/fp-go/exec"
|
||||
F "github.com/ibm/fp-go/function"
|
||||
GE "github.com/ibm/fp-go/internal/exec"
|
||||
)
|
||||
|
||||
var (
|
||||
// Command executes a command
|
||||
// use this version if the command does not produce any side effect, i.e. if the output is uniquely determined by by the input
|
||||
// typically you'd rather use the ReaderIOEither version of the command
|
||||
Command = F.Curry3(command)
|
||||
)
|
||||
|
||||
func command(name string, args []string, in []byte) RE.ReaderEither[exec.CommandOutput] {
|
||||
return func(ctx context.Context) E.Either[error, exec.CommandOutput] {
|
||||
return E.TryCatchError(func() (exec.CommandOutput, error) {
|
||||
return GE.Exec(ctx, name, args, in)
|
||||
})
|
||||
}
|
||||
}
|
26
context/readereither/from.go
Normal file
26
context/readereither/from.go
Normal file
@ -0,0 +1,26 @@
|
||||
package readereither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
RE "github.com/ibm/fp-go/readereither/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func From0[A any](f func(context.Context) (A, error)) ReaderEither[A] {
|
||||
return RE.From0[ReaderEither[A]](f)
|
||||
}
|
||||
|
||||
func From1[T1, A any](f func(context.Context, T1) (A, error)) func(T1) ReaderEither[A] {
|
||||
return RE.From1[ReaderEither[A]](f)
|
||||
}
|
||||
|
||||
func From2[T1, T2, A any](f func(context.Context, T1, T2) (A, error)) func(T1, T2) ReaderEither[A] {
|
||||
return RE.From2[ReaderEither[A]](f)
|
||||
}
|
||||
|
||||
func From3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) (A, error)) func(T1, T2, T3) ReaderEither[A] {
|
||||
return RE.From3[ReaderEither[A]](f)
|
||||
}
|
106
context/readereither/reader.go
Normal file
106
context/readereither/reader.go
Normal file
@ -0,0 +1,106 @@
|
||||
package readereither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/ibm/fp-go/context/reader"
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
O "github.com/ibm/fp-go/option"
|
||||
RE "github.com/ibm/fp-go/readereither/generic"
|
||||
)
|
||||
|
||||
func MakeReaderEither[A any](f func(context.Context) ET.Either[error, A]) ReaderEither[A] {
|
||||
return RE.MakeReaderEither[ReaderEither[A]](f)
|
||||
}
|
||||
|
||||
func FromEither[A any](e ET.Either[error, A]) ReaderEither[A] {
|
||||
return RE.FromEither[ReaderEither[A]](e)
|
||||
}
|
||||
|
||||
func RightReader[A any](r R.Reader[A]) ReaderEither[A] {
|
||||
return RE.RightReader[R.Reader[A], ReaderEither[A]](r)
|
||||
}
|
||||
|
||||
func LeftReader[A any](l R.Reader[error]) ReaderEither[A] {
|
||||
return RE.LeftReader[R.Reader[error], ReaderEither[A]](l)
|
||||
}
|
||||
|
||||
func Left[A any](l error) ReaderEither[A] {
|
||||
return RE.Left[ReaderEither[A]](l)
|
||||
}
|
||||
|
||||
func Right[A any](r A) ReaderEither[A] {
|
||||
return RE.Right[ReaderEither[A]](r)
|
||||
}
|
||||
|
||||
func FromReader[A any](r R.Reader[A]) ReaderEither[A] {
|
||||
return RE.FromReader[R.Reader[A], ReaderEither[A]](r)
|
||||
}
|
||||
|
||||
func MonadMap[A, B any](fa ReaderEither[A], f func(A) B) ReaderEither[B] {
|
||||
return RE.MonadMap[ReaderEither[A], ReaderEither[B]](fa, f)
|
||||
}
|
||||
|
||||
func Map[A, B any](f func(A) B) func(ReaderEither[A]) ReaderEither[B] {
|
||||
return RE.Map[ReaderEither[A], ReaderEither[B]](f)
|
||||
}
|
||||
|
||||
func MonadChain[A, B any](ma ReaderEither[A], f func(A) ReaderEither[B]) ReaderEither[B] {
|
||||
return RE.MonadChain(ma, f)
|
||||
}
|
||||
|
||||
func Chain[A, B any](f func(A) ReaderEither[B]) func(ReaderEither[A]) ReaderEither[B] {
|
||||
return RE.Chain[ReaderEither[A]](f)
|
||||
}
|
||||
|
||||
func Of[A any](a A) ReaderEither[A] {
|
||||
return RE.Of[ReaderEither[A]](a)
|
||||
}
|
||||
|
||||
func MonadAp[A, B any](fab ReaderEither[func(A) B], fa ReaderEither[A]) ReaderEither[B] {
|
||||
return RE.MonadAp[ReaderEither[A], ReaderEither[B]](fab, fa)
|
||||
}
|
||||
|
||||
func Ap[A, B any](fa ReaderEither[A]) func(ReaderEither[func(A) B]) ReaderEither[B] {
|
||||
return RE.Ap[ReaderEither[A], ReaderEither[B], ReaderEither[func(A) B]](fa)
|
||||
}
|
||||
|
||||
func FromPredicate[A any](pred func(A) bool, onFalse func(A) error) func(A) ReaderEither[A] {
|
||||
return RE.FromPredicate[ReaderEither[A]](pred, onFalse)
|
||||
}
|
||||
|
||||
func Fold[A, B any](onLeft func(error) R.Reader[B], onRight func(A) R.Reader[B]) func(ReaderEither[A]) R.Reader[B] {
|
||||
return RE.Fold[ReaderEither[A]](onLeft, onRight)
|
||||
}
|
||||
|
||||
func GetOrElse[A any](onLeft func(error) R.Reader[A]) func(ReaderEither[A]) R.Reader[A] {
|
||||
return RE.GetOrElse[ReaderEither[A]](onLeft)
|
||||
}
|
||||
|
||||
func OrElse[A any](onLeft func(error) ReaderEither[A]) func(ReaderEither[A]) ReaderEither[A] {
|
||||
return RE.OrElse[ReaderEither[A]](onLeft)
|
||||
}
|
||||
|
||||
func OrLeft[A any](onLeft func(error) R.Reader[error]) func(ReaderEither[A]) ReaderEither[A] {
|
||||
return RE.OrLeft[ReaderEither[A], ReaderEither[A]](onLeft)
|
||||
}
|
||||
|
||||
func Ask() ReaderEither[context.Context] {
|
||||
return RE.Ask[ReaderEither[context.Context]]()
|
||||
}
|
||||
|
||||
func Asks[A any](r R.Reader[A]) ReaderEither[A] {
|
||||
return RE.Asks[R.Reader[A], ReaderEither[A]](r)
|
||||
}
|
||||
|
||||
func MonadChainEitherK[A, B any](ma ReaderEither[A], f func(A) ET.Either[error, B]) ReaderEither[B] {
|
||||
return RE.MonadChainEitherK[ReaderEither[A], ReaderEither[B]](ma, f)
|
||||
}
|
||||
|
||||
func ChainEitherK[A, B any](f func(A) ET.Either[error, B]) func(ma ReaderEither[A]) ReaderEither[B] {
|
||||
return RE.ChainEitherK[ReaderEither[A], ReaderEither[B]](f)
|
||||
}
|
||||
|
||||
func ChainOptionK[A, B any](onNone func() error) func(func(A) O.Option[B]) func(ReaderEither[A]) ReaderEither[B] {
|
||||
return RE.ChainOptionK[ReaderEither[A], ReaderEither[B]](onNone)
|
||||
}
|
42
context/readereither/sequence.go
Normal file
42
context/readereither/sequence.go
Normal file
@ -0,0 +1,42 @@
|
||||
package readereither
|
||||
|
||||
import (
|
||||
RE "github.com/ibm/fp-go/readereither/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 ReaderEither[A]) ReaderEither[T.Tuple1[A]] {
|
||||
return RE.SequenceT1[
|
||||
ReaderEither[A],
|
||||
ReaderEither[T.Tuple1[A]],
|
||||
](a)
|
||||
}
|
||||
|
||||
func SequenceT2[A, B any](a ReaderEither[A], b ReaderEither[B]) ReaderEither[T.Tuple2[A, B]] {
|
||||
return RE.SequenceT2[
|
||||
ReaderEither[A],
|
||||
ReaderEither[B],
|
||||
ReaderEither[T.Tuple2[A, B]],
|
||||
](a, b)
|
||||
}
|
||||
|
||||
func SequenceT3[A, B, C any](a ReaderEither[A], b ReaderEither[B], c ReaderEither[C]) ReaderEither[T.Tuple3[A, B, C]] {
|
||||
return RE.SequenceT3[
|
||||
ReaderEither[A],
|
||||
ReaderEither[B],
|
||||
ReaderEither[C],
|
||||
ReaderEither[T.Tuple3[A, B, C]],
|
||||
](a, b, c)
|
||||
}
|
||||
|
||||
func SequenceT4[A, B, C, D any](a ReaderEither[A], b ReaderEither[B], c ReaderEither[C], d ReaderEither[D]) ReaderEither[T.Tuple4[A, B, C, D]] {
|
||||
return RE.SequenceT4[
|
||||
ReaderEither[A],
|
||||
ReaderEither[B],
|
||||
ReaderEither[C],
|
||||
ReaderEither[D],
|
||||
ReaderEither[T.Tuple4[A, B, C, D]],
|
||||
](a, b, c, d)
|
||||
}
|
11
context/readereither/type.go
Normal file
11
context/readereither/type.go
Normal file
@ -0,0 +1,11 @@
|
||||
// Package readereither implements a specialization of the Reader monad assuming a golang context as the context of the monad and a standard golang error
|
||||
package readereither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
RE "github.com/ibm/fp-go/readereither"
|
||||
)
|
||||
|
||||
// ReaderEither is a specialization of the Reader monad for the typical golang scenario
|
||||
type ReaderEither[A any] RE.ReaderEither[context.Context, error, A]
|
16
context/readerio/array.go
Normal file
16
context/readerio/array.go
Normal file
@ -0,0 +1,16 @@
|
||||
package readerio
|
||||
|
||||
import (
|
||||
IO "github.com/ibm/fp-go/io"
|
||||
R "github.com/ibm/fp-go/readerio/generic"
|
||||
)
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func TraverseArray[A, B any](f func(A) ReaderIO[B]) func([]A) ReaderIO[[]B] {
|
||||
return R.TraverseArray[ReaderIO[B], ReaderIO[[]B], IO.IO[B], IO.IO[[]B], []A](f)
|
||||
}
|
||||
|
||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArray[A any](ma []ReaderIO[A]) ReaderIO[[]A] {
|
||||
return R.SequenceArray[ReaderIO[A], ReaderIO[[]A]](ma)
|
||||
}
|
27
context/readerio/from.go
Normal file
27
context/readerio/from.go
Normal file
@ -0,0 +1,27 @@
|
||||
package readerio
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
IO "github.com/ibm/fp-go/io"
|
||||
R "github.com/ibm/fp-go/readerio/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func From0[A any](f func(context.Context) IO.IO[A]) ReaderIO[A] {
|
||||
return R.From0[ReaderIO[A]](f)
|
||||
}
|
||||
|
||||
func From1[T1, A any](f func(context.Context, T1) IO.IO[A]) func(T1) ReaderIO[A] {
|
||||
return R.From1[ReaderIO[A]](f)
|
||||
}
|
||||
|
||||
func From2[T1, T2, A any](f func(context.Context, T1, T2) IO.IO[A]) func(T1, T2) ReaderIO[A] {
|
||||
return R.From2[ReaderIO[A]](f)
|
||||
}
|
||||
|
||||
func From3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) IO.IO[A]) func(T1, T2, T3) ReaderIO[A] {
|
||||
return R.From3[ReaderIO[A]](f)
|
||||
}
|
44
context/readerio/reader.go
Normal file
44
context/readerio/reader.go
Normal file
@ -0,0 +1,44 @@
|
||||
package readerio
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/ibm/fp-go/readerio/generic"
|
||||
)
|
||||
|
||||
func MonadMap[A, B any](fa ReaderIO[A], f func(A) B) ReaderIO[B] {
|
||||
return R.MonadMap[ReaderIO[A], ReaderIO[B]](fa, f)
|
||||
}
|
||||
|
||||
func Map[A, B any](f func(A) B) func(ReaderIO[A]) ReaderIO[B] {
|
||||
return R.Map[ReaderIO[A], ReaderIO[B]](f)
|
||||
}
|
||||
|
||||
func MonadChain[A, B any](ma ReaderIO[A], f func(A) ReaderIO[B]) ReaderIO[B] {
|
||||
return R.MonadChain(ma, f)
|
||||
}
|
||||
|
||||
func Chain[A, B any](f func(A) ReaderIO[B]) func(ReaderIO[A]) ReaderIO[B] {
|
||||
return R.Chain[ReaderIO[A]](f)
|
||||
}
|
||||
|
||||
func Of[A any](a A) ReaderIO[A] {
|
||||
return R.Of[ReaderIO[A]](a)
|
||||
}
|
||||
|
||||
func MonadAp[A, B any](fab ReaderIO[func(A) B], fa ReaderIO[A]) ReaderIO[B] {
|
||||
return R.MonadAp[ReaderIO[A], ReaderIO[B]](fab, fa)
|
||||
}
|
||||
|
||||
func Ap[A, B any](fa ReaderIO[A]) func(ReaderIO[func(A) B]) ReaderIO[B] {
|
||||
return R.Ap[ReaderIO[A], ReaderIO[B], ReaderIO[func(A) B]](fa)
|
||||
}
|
||||
|
||||
func Ask() ReaderIO[context.Context] {
|
||||
return R.Ask[ReaderIO[context.Context]]()
|
||||
}
|
||||
|
||||
// Defer creates an IO by creating a brand new IO via a generator function, each time
|
||||
func Defer[A any](gen func() ReaderIO[A]) ReaderIO[A] {
|
||||
return R.Defer[ReaderIO[A]](gen)
|
||||
}
|
65
context/readerio/reader_test.go
Normal file
65
context/readerio/reader_test.go
Normal file
@ -0,0 +1,65 @@
|
||||
package readerio
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
F "github.com/ibm/fp-go/function"
|
||||
IO "github.com/ibm/fp-go/io"
|
||||
T "github.com/ibm/fp-go/tuple"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func GoFunction(ctx context.Context, data string) IO.IO[string] {
|
||||
return func() string {
|
||||
return strings.ToUpper(data)
|
||||
}
|
||||
}
|
||||
|
||||
func GoIntFunction(ctx context.Context, data string, number int) IO.IO[string] {
|
||||
return func() string {
|
||||
return fmt.Sprintf("%s: %d", data, number)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReaderFrom(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
f := From1(GoFunction)
|
||||
|
||||
result := f("input")(ctx)
|
||||
|
||||
assert.Equal(t, result(), "INPUT")
|
||||
|
||||
}
|
||||
|
||||
func MyFinalResult(left, right string) string {
|
||||
return fmt.Sprintf("%s-%s", left, right)
|
||||
}
|
||||
|
||||
func TestReadersFrom(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
f1 := From1(GoFunction)
|
||||
f2 := From2(GoIntFunction)
|
||||
|
||||
result1 := f1("input")(ctx)
|
||||
result2 := f2("input", 10)(ctx)
|
||||
|
||||
result3 := MyFinalResult(result1(), result2())
|
||||
|
||||
h := F.Pipe1(
|
||||
SequenceT2(f1("input"), f2("input", 10)),
|
||||
Map(T.Tupled2(MyFinalResult)),
|
||||
)
|
||||
|
||||
composedResult := h(ctx)
|
||||
|
||||
assert.Equal(t, result1(), "INPUT")
|
||||
assert.Equal(t, result2(), "input: 10")
|
||||
assert.Equal(t, result3, "INPUT-input: 10")
|
||||
|
||||
assert.Equal(t, composedResult(), "INPUT-input: 10")
|
||||
|
||||
}
|
42
context/readerio/sequence.go
Normal file
42
context/readerio/sequence.go
Normal file
@ -0,0 +1,42 @@
|
||||
package readerio
|
||||
|
||||
import (
|
||||
R "github.com/ibm/fp-go/readerio/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 ReaderIO[A]) ReaderIO[T.Tuple1[A]] {
|
||||
return R.SequenceT1[
|
||||
ReaderIO[A],
|
||||
ReaderIO[T.Tuple1[A]],
|
||||
](a)
|
||||
}
|
||||
|
||||
func SequenceT2[A, B any](a ReaderIO[A], b ReaderIO[B]) ReaderIO[T.Tuple2[A, B]] {
|
||||
return R.SequenceT2[
|
||||
ReaderIO[A],
|
||||
ReaderIO[B],
|
||||
ReaderIO[T.Tuple2[A, B]],
|
||||
](a, b)
|
||||
}
|
||||
|
||||
func SequenceT3[A, B, C any](a ReaderIO[A], b ReaderIO[B], c ReaderIO[C]) ReaderIO[T.Tuple3[A, B, C]] {
|
||||
return R.SequenceT3[
|
||||
ReaderIO[A],
|
||||
ReaderIO[B],
|
||||
ReaderIO[C],
|
||||
ReaderIO[T.Tuple3[A, B, C]],
|
||||
](a, b, c)
|
||||
}
|
||||
|
||||
func SequenceT4[A, B, C, D any](a ReaderIO[A], b ReaderIO[B], c ReaderIO[C], d ReaderIO[D]) ReaderIO[T.Tuple4[A, B, C, D]] {
|
||||
return R.SequenceT4[
|
||||
ReaderIO[A],
|
||||
ReaderIO[B],
|
||||
ReaderIO[C],
|
||||
ReaderIO[D],
|
||||
ReaderIO[T.Tuple4[A, B, C, D]],
|
||||
](a, b, c, d)
|
||||
}
|
11
context/readerio/type.go
Normal file
11
context/readerio/type.go
Normal file
@ -0,0 +1,11 @@
|
||||
// Package readerio implements a specialization of the ReaderIO monad assuming a golang context as the context of the monad
|
||||
package readerio
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/ibm/fp-go/readerio"
|
||||
)
|
||||
|
||||
// ReaderIO is a specialization of the ReaderIO monad assuming a golang context as the context of the monad
|
||||
type ReaderIO[A any] R.ReaderIO[context.Context, A]
|
18
context/readerioeither/cancel.go
Normal file
18
context/readerioeither/cancel.go
Normal file
@ -0,0 +1,18 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
CIOE "github.com/ibm/fp-go/context/ioeither"
|
||||
IOE "github.com/ibm/fp-go/ioeither"
|
||||
)
|
||||
|
||||
// withContext wraps an existing ReaderIOEither and performs a context check for cancellation before delegating
|
||||
func WithContext[A any](ma ReaderIOEither[A]) ReaderIOEither[A] {
|
||||
return func(ctx context.Context) IOE.IOEither[error, A] {
|
||||
if err := context.Cause(ctx); err != nil {
|
||||
return IOE.Left[A](err)
|
||||
}
|
||||
return CIOE.WithContext(ctx, ma(ctx))
|
||||
}
|
||||
}
|
30
context/readerioeither/eitherize.go
Normal file
30
context/readerioeither/eitherize.go
Normal file
@ -0,0 +1,30 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
RE "github.com/ibm/fp-go/readerioeither/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func Eitherize0[A any](f func(context.Context) (A, error)) ReaderIOEither[A] {
|
||||
return RE.Eitherize0[ReaderIOEither[A]](f)
|
||||
}
|
||||
|
||||
func Eitherize1[T1, A any](f func(context.Context, T1) (A, error)) func(T1) ReaderIOEither[A] {
|
||||
return RE.Eitherize1[ReaderIOEither[A]](f)
|
||||
}
|
||||
|
||||
func Eitherize2[T1, T2, A any](f func(context.Context, T1, T2) (A, error)) func(T1, T2) ReaderIOEither[A] {
|
||||
return RE.Eitherize2[ReaderIOEither[A]](f)
|
||||
}
|
||||
|
||||
func Eitherize3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) (A, error)) func(T1, T2, T3) ReaderIOEither[A] {
|
||||
return RE.Eitherize3[ReaderIOEither[A]](f)
|
||||
}
|
||||
|
||||
func Eitherize4[T1, T2, T3, T4, A any](f func(context.Context, T1, T2, T3, T4) (A, error)) func(T1, T2, T3, T4) ReaderIOEither[A] {
|
||||
return RE.Eitherize4[ReaderIOEither[A]](f)
|
||||
}
|
14
context/readerioeither/eq.go
Normal file
14
context/readerioeither/eq.go
Normal file
@ -0,0 +1,14 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
EQ "github.com/ibm/fp-go/eq"
|
||||
G "github.com/ibm/fp-go/readerioeither/generic"
|
||||
)
|
||||
|
||||
// Eq implements the equals predicate for values contained in the IOEither monad
|
||||
func Eq[A any](eq EQ.Eq[ET.Either[error, A]]) func(context.Context) EQ.Eq[ReaderIOEither[A]] {
|
||||
return G.Eq[ReaderIOEither[A]](eq)
|
||||
}
|
24
context/readerioeither/exec/exec.go
Normal file
24
context/readerioeither/exec/exec.go
Normal file
@ -0,0 +1,24 @@
|
||||
package exec
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
RIOE "github.com/ibm/fp-go/context/readerioeither"
|
||||
"github.com/ibm/fp-go/exec"
|
||||
F "github.com/ibm/fp-go/function"
|
||||
GE "github.com/ibm/fp-go/internal/exec"
|
||||
IOE "github.com/ibm/fp-go/ioeither"
|
||||
)
|
||||
|
||||
var (
|
||||
// Command executes a cancelable command
|
||||
Command = F.Curry3(command)
|
||||
)
|
||||
|
||||
func command(name string, args []string, in []byte) RIOE.ReaderIOEither[exec.CommandOutput] {
|
||||
return func(ctx context.Context) IOE.IOEither[error, exec.CommandOutput] {
|
||||
return IOE.TryCatchError(func() (exec.CommandOutput, error) {
|
||||
return GE.Exec(ctx, name, args, in)
|
||||
})
|
||||
}
|
||||
}
|
43
context/readerioeither/file/file.go
Normal file
43
context/readerioeither/file/file.go
Normal file
@ -0,0 +1,43 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
RIOE "github.com/ibm/fp-go/context/readerioeither"
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
F "github.com/ibm/fp-go/function"
|
||||
"github.com/ibm/fp-go/internal/file"
|
||||
IOE "github.com/ibm/fp-go/ioeither"
|
||||
)
|
||||
|
||||
var (
|
||||
openIOE = IOE.Eitherize1(os.Open)
|
||||
// Open opens a file for reading within the given context
|
||||
Open = F.Flow3(
|
||||
openIOE,
|
||||
RIOE.FromIOEither[*os.File],
|
||||
RIOE.WithContext[*os.File],
|
||||
)
|
||||
)
|
||||
|
||||
// Close closes an object
|
||||
func Close[C io.Closer](c C) RIOE.ReaderIOEither[any] {
|
||||
return RIOE.FromIOEither(func() ET.Either[error, any] {
|
||||
return ET.TryCatchError(func() (any, error) {
|
||||
return c, c.Close()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// ReadFile reads a file in the scope of a context
|
||||
func ReadFile(path string) RIOE.ReaderIOEither[[]byte] {
|
||||
return RIOE.WithResource[*os.File, []byte](Open(path), Close[*os.File])(func(r *os.File) RIOE.ReaderIOEither[[]byte] {
|
||||
return func(ctx context.Context) IOE.IOEither[error, []byte] {
|
||||
return IOE.MakeIO(func() ET.Either[error, []byte] {
|
||||
return file.ReadAll(ctx, r)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
30
context/readerioeither/from.go
Normal file
30
context/readerioeither/from.go
Normal file
@ -0,0 +1,30 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
RE "github.com/ibm/fp-go/readerioeither/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func From0[A any](f func(context.Context) func() (A, error)) ReaderIOEither[A] {
|
||||
return RE.From0[ReaderIOEither[A]](f)
|
||||
}
|
||||
|
||||
func From1[T1, A any](f func(context.Context, T1) func() (A, error)) func(T1) ReaderIOEither[A] {
|
||||
return RE.From1[ReaderIOEither[A]](f)
|
||||
}
|
||||
|
||||
func From2[T1, T2, A any](f func(context.Context, T1, T2) func() (A, error)) func(T1, T2) ReaderIOEither[A] {
|
||||
return RE.From2[ReaderIOEither[A]](f)
|
||||
}
|
||||
|
||||
func From3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) func() (A, error)) func(T1, T2, T3) ReaderIOEither[A] {
|
||||
return RE.From3[ReaderIOEither[A]](f)
|
||||
}
|
||||
|
||||
func From4[T1, T2, T3, T4, A any](f func(context.Context, T1, T2, T3, T4) func() (A, error)) func(T1, T2, T3, T4) ReaderIOEither[A] {
|
||||
return RE.From4[ReaderIOEither[A]](f)
|
||||
}
|
78
context/readerioeither/http/request.go
Normal file
78
context/readerioeither/http/request.go
Normal file
@ -0,0 +1,78 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
B "github.com/ibm/fp-go/bytes"
|
||||
RIOE "github.com/ibm/fp-go/context/readerioeither"
|
||||
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 (
|
||||
// Requester is a reader that constructs a request
|
||||
Requester = RIOE.ReaderIOEither[*http.Request]
|
||||
|
||||
Client interface {
|
||||
// Do can send an HTTP request considering a context
|
||||
Do(Requester) RIOE.ReaderIOEither[*http.Response]
|
||||
}
|
||||
|
||||
client struct {
|
||||
delegate *http.Client
|
||||
doIOE func(*http.Request) IOE.IOEither[error, *http.Response]
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
NewRequest = RIOE.Eitherize3(http.NewRequestWithContext)
|
||||
)
|
||||
|
||||
func (client client) Do(req Requester) RIOE.ReaderIOEither[*http.Response] {
|
||||
return F.Pipe1(
|
||||
req,
|
||||
RIOE.ChainIOEitherK(client.doIOE),
|
||||
)
|
||||
}
|
||||
|
||||
// MakeClient creates an HTTP client proxy
|
||||
func MakeClient(httpClient *http.Client) Client {
|
||||
return client{delegate: httpClient, doIOE: IOE.Eitherize1(httpClient.Do)}
|
||||
}
|
||||
|
||||
// ReadAll sends a request and reads the response as a byte array
|
||||
func ReadAll(client Client) func(Requester) RIOE.ReaderIOEither[[]byte] {
|
||||
return func(req Requester) RIOE.ReaderIOEither[[]byte] {
|
||||
doReq := client.Do(req)
|
||||
return func(ctx context.Context) IOE.IOEither[error, []byte] {
|
||||
return IOEF.ReadAll(F.Pipe2(
|
||||
ctx,
|
||||
doReq,
|
||||
IOE.Map[error](func(resp *http.Response) io.ReadCloser {
|
||||
return resp.Body
|
||||
}),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReadText sends a request, reads the response and represents the response as a text string
|
||||
func ReadText(client Client) func(Requester) RIOE.ReaderIOEither[string] {
|
||||
return F.Flow2(
|
||||
ReadAll(client),
|
||||
RIOE.Map(B.ToString),
|
||||
)
|
||||
}
|
||||
|
||||
// ReadJson sends a request, reads the response and parses the response as JSON
|
||||
func ReadJson[A any](client Client) func(Requester) RIOE.ReaderIOEither[A] {
|
||||
return F.Flow2(
|
||||
ReadAll(client),
|
||||
RIOE.ChainEitherK(J.Unmarshal[A]),
|
||||
)
|
||||
}
|
31
context/readerioeither/http/request_test.go
Normal file
31
context/readerioeither/http/request_test.go
Normal file
@ -0,0 +1,31 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
H "net/http"
|
||||
)
|
||||
|
||||
type PostItem struct {
|
||||
UserId uint `json:"userId"`
|
||||
Id uint `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
|
||||
func TestSendSingleRequest(t *testing.T) {
|
||||
|
||||
client := MakeClient(H.DefaultClient)
|
||||
|
||||
req1 := NewRequest("GET", "https://jsonplaceholder.typicode.com/posts/1", nil)
|
||||
|
||||
readItem := ReadJson[PostItem](client)
|
||||
|
||||
resp1 := readItem(req1)
|
||||
|
||||
resE := resp1(context.Background())()
|
||||
|
||||
fmt.Println(resE)
|
||||
}
|
219
context/readerioeither/reader.go
Normal file
219
context/readerioeither/reader.go
Normal file
@ -0,0 +1,219 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
R "github.com/ibm/fp-go/context/reader"
|
||||
RIO "github.com/ibm/fp-go/context/readerio"
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
ER "github.com/ibm/fp-go/errors"
|
||||
F "github.com/ibm/fp-go/function"
|
||||
IO "github.com/ibm/fp-go/io"
|
||||
IOE "github.com/ibm/fp-go/ioeither"
|
||||
O "github.com/ibm/fp-go/option"
|
||||
RIE "github.com/ibm/fp-go/readerioeither/generic"
|
||||
)
|
||||
|
||||
func FromEither[A any](e ET.Either[error, A]) ReaderIOEither[A] {
|
||||
return RIE.FromEither[ReaderIOEither[A]](e)
|
||||
}
|
||||
|
||||
func RightReader[A any](r R.Reader[A]) ReaderIOEither[A] {
|
||||
return RIE.RightReader[R.Reader[A], ReaderIOEither[A]](r)
|
||||
}
|
||||
|
||||
func LeftReader[A any](l R.Reader[error]) ReaderIOEither[A] {
|
||||
return RIE.LeftReader[R.Reader[error], ReaderIOEither[A]](l)
|
||||
}
|
||||
|
||||
func Left[A any](l error) ReaderIOEither[A] {
|
||||
return RIE.Left[ReaderIOEither[A]](l)
|
||||
}
|
||||
|
||||
func Right[A any](r A) ReaderIOEither[A] {
|
||||
return RIE.Right[ReaderIOEither[A]](r)
|
||||
}
|
||||
|
||||
func FromReader[A any](r R.Reader[A]) ReaderIOEither[A] {
|
||||
return RIE.FromReader[R.Reader[A], ReaderIOEither[A]](r)
|
||||
}
|
||||
|
||||
func MonadMap[A, B any](fa ReaderIOEither[A], f func(A) B) ReaderIOEither[B] {
|
||||
return RIE.MonadMap[ReaderIOEither[A], ReaderIOEither[B]](fa, f)
|
||||
}
|
||||
|
||||
func Map[A, B any](f func(A) B) func(ReaderIOEither[A]) ReaderIOEither[B] {
|
||||
return RIE.Map[ReaderIOEither[A], ReaderIOEither[B]](f)
|
||||
}
|
||||
|
||||
func MonadChain[A, B any](ma ReaderIOEither[A], f func(A) ReaderIOEither[B]) ReaderIOEither[B] {
|
||||
return RIE.MonadChain(ma, f)
|
||||
}
|
||||
|
||||
func Chain[A, B any](f func(A) ReaderIOEither[B]) func(ReaderIOEither[A]) ReaderIOEither[B] {
|
||||
return RIE.Chain[ReaderIOEither[A]](f)
|
||||
}
|
||||
|
||||
func Of[A any](a A) ReaderIOEither[A] {
|
||||
return RIE.Of[ReaderIOEither[A]](a)
|
||||
}
|
||||
|
||||
// withCancelCauseFunc wraps an IOEither such that in case of an error the cancel function is invoked
|
||||
func withCancelCauseFunc[A any](cancel context.CancelCauseFunc, ma IOE.IOEither[error, A]) IOE.IOEither[error, A] {
|
||||
return F.Pipe3(
|
||||
ma,
|
||||
IOE.Swap[error, A],
|
||||
IOE.ChainFirstIOK[A, error, any](func(err error) IO.IO[any] {
|
||||
return IO.MakeIO(func() any {
|
||||
cancel(err)
|
||||
return nil
|
||||
})
|
||||
}),
|
||||
IOE.Swap[A, error],
|
||||
)
|
||||
}
|
||||
|
||||
// MonadAp implements the `Ap` function for a reader with context. It creates a sub-context that will
|
||||
// be canceled if any of the input operations errors out or
|
||||
func MonadAp[A, B any](fab ReaderIOEither[func(A) B], fa ReaderIOEither[A]) ReaderIOEither[B] {
|
||||
// context sensitive input
|
||||
cfab := WithContext(fab)
|
||||
cfa := WithContext(fa)
|
||||
|
||||
return func(ctx context.Context) IOE.IOEither[error, B] {
|
||||
// quick check for cancellation
|
||||
if err := context.Cause(ctx); err != nil {
|
||||
return IOE.Left[B](err)
|
||||
}
|
||||
|
||||
return func() ET.Either[error, B] {
|
||||
// quick check for cancellation
|
||||
if err := context.Cause(ctx); err != nil {
|
||||
return ET.Left[B](err)
|
||||
}
|
||||
|
||||
// create sub-contexts for fa and fab, so they can cancel one other
|
||||
ctxSub, cancelSub := context.WithCancelCause(ctx)
|
||||
defer cancelSub(nil) // cancel has to be called in all paths
|
||||
|
||||
fabIOE := withCancelCauseFunc(cancelSub, cfab(ctxSub))
|
||||
faIOE := withCancelCauseFunc(cancelSub, cfa(ctxSub))
|
||||
|
||||
return IOE.MonadAp(fabIOE, faIOE)()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Ap[A, B any](fa ReaderIOEither[A]) func(ReaderIOEither[func(A) B]) ReaderIOEither[B] {
|
||||
return F.Bind2nd(MonadAp[A, B], fa)
|
||||
}
|
||||
|
||||
func FromPredicate[A any](pred func(A) bool, onFalse func(A) error) func(A) ReaderIOEither[A] {
|
||||
return RIE.FromPredicate[ReaderIOEither[A]](pred, onFalse)
|
||||
}
|
||||
|
||||
func Fold[A, B any](onLeft func(error) RIO.ReaderIO[B], onRight func(A) RIO.ReaderIO[B]) func(ReaderIOEither[A]) RIO.ReaderIO[B] {
|
||||
return RIE.Fold[RIO.ReaderIO[B], ReaderIOEither[A]](onLeft, onRight)
|
||||
}
|
||||
|
||||
func GetOrElse[A any](onLeft func(error) RIO.ReaderIO[A]) func(ReaderIOEither[A]) RIO.ReaderIO[A] {
|
||||
return RIE.GetOrElse[RIO.ReaderIO[A], ReaderIOEither[A]](onLeft)
|
||||
}
|
||||
|
||||
func OrElse[A any](onLeft func(error) ReaderIOEither[A]) func(ReaderIOEither[A]) ReaderIOEither[A] {
|
||||
return RIE.OrElse[ReaderIOEither[A]](onLeft)
|
||||
}
|
||||
|
||||
func OrLeft[A any](onLeft func(error) RIO.ReaderIO[error]) func(ReaderIOEither[A]) ReaderIOEither[A] {
|
||||
return RIE.OrLeft[ReaderIOEither[A], RIO.ReaderIO[error], ReaderIOEither[A]](onLeft)
|
||||
}
|
||||
|
||||
func Ask() ReaderIOEither[context.Context] {
|
||||
return RIE.Ask[ReaderIOEither[context.Context]]()
|
||||
}
|
||||
|
||||
func Asks[A any](r R.Reader[A]) ReaderIOEither[A] {
|
||||
return RIE.Asks[R.Reader[A], ReaderIOEither[A]](r)
|
||||
}
|
||||
|
||||
func MonadChainEitherK[A, B any](ma ReaderIOEither[A], f func(A) ET.Either[error, B]) ReaderIOEither[B] {
|
||||
return RIE.MonadChainEitherK[ReaderIOEither[A], ReaderIOEither[B]](ma, f)
|
||||
}
|
||||
|
||||
func ChainEitherK[A, B any](f func(A) ET.Either[error, B]) func(ma ReaderIOEither[A]) ReaderIOEither[B] {
|
||||
return RIE.ChainEitherK[ReaderIOEither[A], ReaderIOEither[B]](f)
|
||||
}
|
||||
|
||||
func ChainOptionK[A, B any](onNone func() error) func(func(A) O.Option[B]) func(ReaderIOEither[A]) ReaderIOEither[B] {
|
||||
return RIE.ChainOptionK[ReaderIOEither[A], ReaderIOEither[B]](onNone)
|
||||
}
|
||||
|
||||
func FromIOEither[A any](t IOE.IOEither[error, A]) ReaderIOEither[A] {
|
||||
return RIE.FromIOEither[ReaderIOEither[A]](t)
|
||||
}
|
||||
|
||||
func FromIO[A any](t IO.IO[A]) ReaderIOEither[A] {
|
||||
return RIE.FromIO[ReaderIOEither[A]](t)
|
||||
}
|
||||
|
||||
// Never returns a 'ReaderIOEither' that never returns, except if its context gets canceled
|
||||
func Never[A any]() ReaderIOEither[A] {
|
||||
return func(ctx context.Context) IOE.IOEither[error, A] {
|
||||
return IOE.MakeIO(func() ET.Either[error, A] {
|
||||
<-ctx.Done()
|
||||
return ET.Left[A](context.Cause(ctx))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func MonadChainIOK[A, B any](ma ReaderIOEither[A], f func(A) IO.IO[B]) ReaderIOEither[B] {
|
||||
return RIE.MonadChainIOK[ReaderIOEither[A], ReaderIOEither[B]](ma, f)
|
||||
}
|
||||
|
||||
func ChainIOK[A, B any](f func(A) IO.IO[B]) func(ma ReaderIOEither[A]) ReaderIOEither[B] {
|
||||
return RIE.ChainIOK[ReaderIOEither[A], ReaderIOEither[B]](f)
|
||||
}
|
||||
|
||||
func ChainIOEitherK[A, B any](f func(A) IOE.IOEither[error, B]) func(ma ReaderIOEither[A]) ReaderIOEither[B] {
|
||||
return RIE.ChainIOEitherK[ReaderIOEither[A], ReaderIOEither[B]](f)
|
||||
}
|
||||
|
||||
// Delay creates an operation that passes in the value after some delay
|
||||
func Delay[A any](delay time.Duration) func(ma ReaderIOEither[A]) ReaderIOEither[A] {
|
||||
return func(ma ReaderIOEither[A]) ReaderIOEither[A] {
|
||||
return func(ctx context.Context) IOE.IOEither[error, A] {
|
||||
return IOE.MakeIO(func() ET.Either[error, A] {
|
||||
// manage the timeout
|
||||
timeoutCtx, cancelTimeout := context.WithTimeout(ctx, delay)
|
||||
defer cancelTimeout()
|
||||
// whatever comes first
|
||||
select {
|
||||
case <-timeoutCtx.Done():
|
||||
return ma(ctx)()
|
||||
case <-ctx.Done():
|
||||
return ET.Left[A](context.Cause(ctx))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Timer will return the current time after an initial delay
|
||||
func Timer(delay time.Duration) ReaderIOEither[time.Time] {
|
||||
return F.Pipe2(
|
||||
IO.Now,
|
||||
FromIO[time.Time],
|
||||
Delay[time.Time](delay),
|
||||
)
|
||||
}
|
||||
|
||||
// Defer creates an IO by creating a brand new IO via a generator function, each time
|
||||
func Defer[A any](gen func() ReaderIOEither[A]) ReaderIOEither[A] {
|
||||
return RIE.Defer[ReaderIOEither[A]](gen)
|
||||
}
|
||||
|
||||
// TryCatch wraps a reader returning a tuple as an error into ReaderIOEither
|
||||
func TryCatch[A any](f func(context.Context) func() (A, error)) ReaderIOEither[A] {
|
||||
return RIE.TryCatch[ReaderIOEither[A]](f, ER.IdentityError)
|
||||
}
|
149
context/readerioeither/reader_test.go
Normal file
149
context/readerioeither/reader_test.go
Normal file
@ -0,0 +1,149 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
E "github.com/ibm/fp-go/either"
|
||||
F "github.com/ibm/fp-go/function"
|
||||
"github.com/ibm/fp-go/internal/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestInnerContextCancelSemantics(t *testing.T) {
|
||||
// start with a simple context
|
||||
outer := context.Background()
|
||||
|
||||
parent, parentCancel := context.WithCancel(outer)
|
||||
defer parentCancel()
|
||||
|
||||
inner, innerCancel := context.WithCancel(parent)
|
||||
defer innerCancel()
|
||||
|
||||
assert.NoError(t, parent.Err())
|
||||
assert.NoError(t, inner.Err())
|
||||
|
||||
innerCancel()
|
||||
|
||||
assert.NoError(t, parent.Err())
|
||||
assert.Error(t, inner.Err())
|
||||
|
||||
}
|
||||
|
||||
func TestOuterContextCancelSemantics(t *testing.T) {
|
||||
// start with a simple context
|
||||
outer := context.Background()
|
||||
|
||||
parent, outerCancel := context.WithCancel(outer)
|
||||
defer outerCancel()
|
||||
|
||||
inner, innerCancel := context.WithCancel(parent)
|
||||
defer innerCancel()
|
||||
|
||||
assert.NoError(t, parent.Err())
|
||||
assert.NoError(t, inner.Err())
|
||||
|
||||
outerCancel()
|
||||
|
||||
assert.Error(t, parent.Err())
|
||||
assert.Error(t, inner.Err())
|
||||
|
||||
}
|
||||
|
||||
func TestOuterAndInnerContextCancelSemantics(t *testing.T) {
|
||||
// start with a simple context
|
||||
outer := context.Background()
|
||||
|
||||
parent, outerCancel := context.WithCancel(outer)
|
||||
defer outerCancel()
|
||||
|
||||
inner, innerCancel := context.WithCancel(parent)
|
||||
defer innerCancel()
|
||||
|
||||
assert.NoError(t, parent.Err())
|
||||
assert.NoError(t, inner.Err())
|
||||
|
||||
outerCancel()
|
||||
innerCancel()
|
||||
|
||||
assert.Error(t, parent.Err())
|
||||
assert.Error(t, inner.Err())
|
||||
|
||||
outerCancel()
|
||||
innerCancel()
|
||||
|
||||
assert.Error(t, parent.Err())
|
||||
assert.Error(t, inner.Err())
|
||||
}
|
||||
|
||||
func TestCancelCauseSemantics(t *testing.T) {
|
||||
// start with a simple context
|
||||
outer := context.Background()
|
||||
|
||||
parent, outerCancel := context.WithCancelCause(outer)
|
||||
defer outerCancel(nil)
|
||||
|
||||
inner := context.WithValue(parent, "key", "value")
|
||||
|
||||
assert.NoError(t, parent.Err())
|
||||
assert.NoError(t, inner.Err())
|
||||
|
||||
err := fmt.Errorf("test error")
|
||||
|
||||
outerCancel(err)
|
||||
|
||||
assert.Error(t, parent.Err())
|
||||
assert.Error(t, inner.Err())
|
||||
|
||||
assert.Equal(t, err, context.Cause(parent))
|
||||
assert.Equal(t, err, context.Cause(inner))
|
||||
}
|
||||
|
||||
func TestTimer(t *testing.T) {
|
||||
delta := 3 * time.Second
|
||||
timer := Timer(delta)
|
||||
ctx := context.Background()
|
||||
|
||||
t0 := time.Now()
|
||||
res := timer(ctx)()
|
||||
t1 := time.Now()
|
||||
|
||||
assert.WithinDuration(t, t0.Add(delta), t1, time.Second)
|
||||
assert.True(t, E.IsRight(res))
|
||||
}
|
||||
|
||||
func TestCanceledApply(t *testing.T) {
|
||||
// our error
|
||||
err := fmt.Errorf("TestCanceledApply")
|
||||
// the actual apply value errors out after some time
|
||||
errValue := F.Pipe1(
|
||||
Left[string](err),
|
||||
Delay[string](time.Second),
|
||||
)
|
||||
// function never resolves
|
||||
fct := Never[func(string) string]()
|
||||
// apply the values, we expect an error after 1s
|
||||
|
||||
applied := F.Pipe1(
|
||||
fct,
|
||||
Ap[string, string](errValue),
|
||||
)
|
||||
|
||||
res := applied(context.Background())()
|
||||
assert.Equal(t, E.Left[string](err), res)
|
||||
}
|
||||
|
||||
func TestRegularApply(t *testing.T) {
|
||||
value := Of("Carsten")
|
||||
fct := Of(utils.Upper)
|
||||
|
||||
applied := F.Pipe1(
|
||||
fct,
|
||||
Ap[string, string](value),
|
||||
)
|
||||
|
||||
res := applied(context.Background())()
|
||||
assert.Equal(t, E.Of[error]("CARSTEN"), res)
|
||||
}
|
15
context/readerioeither/resource.go
Normal file
15
context/readerioeither/resource.go
Normal file
@ -0,0 +1,15 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
F "github.com/ibm/fp-go/function"
|
||||
RIE "github.com/ibm/fp-go/readerioeither/generic"
|
||||
)
|
||||
|
||||
// WithResource constructs a function that creates a resource, then operates on it and then releases the resource
|
||||
func WithResource[R, A any](onCreate ReaderIOEither[R], onRelease func(R) ReaderIOEither[any]) func(func(R) ReaderIOEither[A]) ReaderIOEither[A] {
|
||||
// wraps the callback functions with a context check
|
||||
return F.Flow2(
|
||||
F.Bind2nd(F.Flow2[func(R) ReaderIOEither[A], func(ReaderIOEither[A]) ReaderIOEither[A], R, ReaderIOEither[A], ReaderIOEither[A]], WithContext[A]),
|
||||
RIE.WithResource[ReaderIOEither[A]](WithContext(onCreate), onRelease),
|
||||
)
|
||||
}
|
42
context/readerioeither/sequence.go
Normal file
42
context/readerioeither/sequence.go
Normal file
@ -0,0 +1,42 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
RE "github.com/ibm/fp-go/readerioeither/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 ReaderIOEither[A]) ReaderIOEither[T.Tuple1[A]] {
|
||||
return RE.SequenceT1[
|
||||
ReaderIOEither[A],
|
||||
ReaderIOEither[T.Tuple1[A]],
|
||||
](a)
|
||||
}
|
||||
|
||||
func SequenceT2[A, B any](a ReaderIOEither[A], b ReaderIOEither[B]) ReaderIOEither[T.Tuple2[A, B]] {
|
||||
return RE.SequenceT2[
|
||||
ReaderIOEither[A],
|
||||
ReaderIOEither[B],
|
||||
ReaderIOEither[T.Tuple2[A, B]],
|
||||
](a, b)
|
||||
}
|
||||
|
||||
func SequenceT3[A, B, C any](a ReaderIOEither[A], b ReaderIOEither[B], c ReaderIOEither[C]) ReaderIOEither[T.Tuple3[A, B, C]] {
|
||||
return RE.SequenceT3[
|
||||
ReaderIOEither[A],
|
||||
ReaderIOEither[B],
|
||||
ReaderIOEither[C],
|
||||
ReaderIOEither[T.Tuple3[A, B, C]],
|
||||
](a, b, c)
|
||||
}
|
||||
|
||||
func SequenceT4[A, B, C, D any](a ReaderIOEither[A], b ReaderIOEither[B], c ReaderIOEither[C], d ReaderIOEither[D]) ReaderIOEither[T.Tuple4[A, B, C, D]] {
|
||||
return RE.SequenceT4[
|
||||
ReaderIOEither[A],
|
||||
ReaderIOEither[B],
|
||||
ReaderIOEither[C],
|
||||
ReaderIOEither[D],
|
||||
ReaderIOEither[T.Tuple4[A, B, C, D]],
|
||||
](a, b, c, d)
|
||||
}
|
26
context/readerioeither/traverse.go
Normal file
26
context/readerioeither/traverse.go
Normal file
@ -0,0 +1,26 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
IOE "github.com/ibm/fp-go/ioeither"
|
||||
RE "github.com/ibm/fp-go/readerioeither/generic"
|
||||
)
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func TraverseArray[A, B any](f func(A) ReaderIOEither[B]) func([]A) ReaderIOEither[[]B] {
|
||||
return RE.TraverseArray[ReaderIOEither[B], ReaderIOEither[[]B], IOE.IOEither[error, B], IOE.IOEither[error, []B], []A](f)
|
||||
}
|
||||
|
||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArray[A any](ma []ReaderIOEither[A]) ReaderIOEither[[]A] {
|
||||
return RE.SequenceArray[ReaderIOEither[A], ReaderIOEither[[]A]](ma)
|
||||
}
|
||||
|
||||
// TraverseRecord transforms a record
|
||||
func TraverseRecord[K comparable, A, B any](f func(A) ReaderIOEither[B]) func(map[K]A) ReaderIOEither[map[K]B] {
|
||||
return RE.TraverseRecord[ReaderIOEither[B], ReaderIOEither[map[K]B], IOE.IOEither[error, B], IOE.IOEither[error, map[K]B], map[K]A](f)
|
||||
}
|
||||
|
||||
// SequenceRecord converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceRecord[K comparable, A any](ma map[K]ReaderIOEither[A]) ReaderIOEither[map[K]A] {
|
||||
return RE.SequenceRecord[ReaderIOEither[A], ReaderIOEither[map[K]A]](ma)
|
||||
}
|
11
context/readerioeither/type.go
Normal file
11
context/readerioeither/type.go
Normal file
@ -0,0 +1,11 @@
|
||||
// Package readerioeither implements a specialization of the Reader monad assuming a golang context as the context of the monad and a standard golang error
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
RE "github.com/ibm/fp-go/readerioeither"
|
||||
)
|
||||
|
||||
// ReaderIOEither is a specialization of the Reader monad for the typical golang scenario
|
||||
type ReaderIOEither[A any] RE.ReaderIOEither[context.Context, error, A]
|
@ -1,4 +1,4 @@
|
||||
package Exec
|
||||
package exec
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -1,21 +1,21 @@
|
||||
package either
|
||||
|
||||
import (
|
||||
Apply "github.com/ibm/fp-go/internal/apply"
|
||||
"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[E, A any](a Either[E, A]) Either[E, T.Tuple1[A]] {
|
||||
return Apply.SequenceT1(
|
||||
return apply.SequenceT1(
|
||||
Map[E, A, T.Tuple1[A]],
|
||||
a,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceT2[E, A, B any](a Either[E, A], b Either[E, B]) Either[E, T.Tuple2[A, B]] {
|
||||
return Apply.SequenceT2(
|
||||
return apply.SequenceT2(
|
||||
Map[E, A, func(B) T.Tuple2[A, B]],
|
||||
Ap[T.Tuple2[A, B], E, B],
|
||||
|
||||
@ -24,7 +24,7 @@ func SequenceT2[E, A, B any](a Either[E, A], b Either[E, B]) Either[E, T.Tuple2[
|
||||
}
|
||||
|
||||
func SequenceT3[E, A, B, C any](a Either[E, A], b Either[E, B], c Either[E, C]) Either[E, T.Tuple3[A, B, C]] {
|
||||
return Apply.SequenceT3(
|
||||
return apply.SequenceT3(
|
||||
Map[E, A, func(B) func(C) T.Tuple3[A, B, C]],
|
||||
Ap[func(C) T.Tuple3[A, B, C], E, B],
|
||||
Ap[T.Tuple3[A, B, C], E, C],
|
||||
@ -34,7 +34,7 @@ func SequenceT3[E, A, B, C any](a Either[E, A], b Either[E, B], c Either[E, C])
|
||||
}
|
||||
|
||||
func SequenceT4[E, A, B, C, D any](a Either[E, A], b Either[E, B], c Either[E, C], d Either[E, D]) Either[E, T.Tuple4[A, B, C, D]] {
|
||||
return Apply.SequenceT4(
|
||||
return apply.SequenceT4(
|
||||
Map[E, A, func(B) func(C) func(D) T.Tuple4[A, B, C, D]],
|
||||
Ap[func(C) func(D) T.Tuple4[A, B, C, D], E, B],
|
||||
Ap[func(D) T.Tuple4[A, B, C, D], E, C],
|
||||
|
41
internal/fromioeither/ioeither.go
Normal file
41
internal/fromioeither/ioeither.go
Normal file
@ -0,0 +1,41 @@
|
||||
package fromioeither
|
||||
|
||||
import (
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
F "github.com/ibm/fp-go/function"
|
||||
C "github.com/ibm/fp-go/internal/chain"
|
||||
)
|
||||
|
||||
func MonadChainFirstIOEitherK[GIOB ~func() ET.Either[E, B], E, A, B, HKTA, HKTB any](
|
||||
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 ChainFirstIOEitherK[GIOB ~func() ET.Either[E, B], E, A, B, HKTA, HKTB any](
|
||||
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 MonadChainIOEitherK[GIOB ~func() ET.Either[E, B], E, A, B, HKTA, HKTB any](
|
||||
mchain func(HKTA, func(A) HKTB) HKTB,
|
||||
fromio func(GIOB) HKTB,
|
||||
first HKTA, f func(A) GIOB) HKTB {
|
||||
// chain
|
||||
return C.MonadChain[A, B](mchain, first, F.Flow2(f, fromio))
|
||||
}
|
||||
|
||||
func ChainIOEitherK[GIOB ~func() ET.Either[E, B], E, A, B, HKTA, HKTB any](
|
||||
mchain func(HKTA, func(A) HKTB) HKTB,
|
||||
fromio func(GIOB) HKTB,
|
||||
f func(A) GIOB) func(HKTA) HKTB {
|
||||
// chain
|
||||
return C.Chain[A, B](mchain, F.Flow2(f, fromio))
|
||||
}
|
39
internal/fromreader/reader.go
Normal file
39
internal/fromreader/reader.go
Normal file
@ -0,0 +1,39 @@
|
||||
package fromreader
|
||||
|
||||
import (
|
||||
F "github.com/ibm/fp-go/function"
|
||||
G "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
func Ask[GR ~func(R) R, R, HKTRA any](fromReader func(GR) HKTRA) func() HKTRA {
|
||||
return func() HKTRA {
|
||||
return fromReader(G.Ask[GR]())
|
||||
}
|
||||
}
|
||||
|
||||
func Asks[GA ~func(R) A, R, A, HKTRA any](fromReader func(GA) HKTRA) func(GA) HKTRA {
|
||||
return fromReader
|
||||
}
|
||||
|
||||
func FromReaderK[GB ~func(R) B, R, A, B, HKTRB any](
|
||||
fromReader func(GB) HKTRB,
|
||||
f func(A) GB) func(A) HKTRB {
|
||||
return F.Flow2(f, fromReader)
|
||||
}
|
||||
|
||||
func MonadChainReaderK[GB ~func(R) B, R, A, B, HKTRA, HKTRB any](
|
||||
mchain func(HKTRA, func(A) HKTRB) HKTRB,
|
||||
fromReader func(GB) HKTRB,
|
||||
ma HKTRA,
|
||||
f func(A) GB,
|
||||
) HKTRB {
|
||||
return mchain(ma, FromReaderK(fromReader, f))
|
||||
}
|
||||
|
||||
func ChainReaderK[GB ~func(R) B, R, A, B, HKTRA, HKTRB any](
|
||||
mchain func(HKTRA, func(A) HKTRB) HKTRB,
|
||||
fromReader func(GB) HKTRB,
|
||||
f func(A) GB,
|
||||
) func(HKTRA) HKTRB {
|
||||
return F.Bind2nd(mchain, FromReaderK(fromReader, f))
|
||||
}
|
44
internal/readert/reader.go
Normal file
44
internal/readert/reader.go
Normal file
@ -0,0 +1,44 @@
|
||||
package readert
|
||||
|
||||
import (
|
||||
F "github.com/ibm/fp-go/function"
|
||||
R "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
// here we implement the monadic operations using callbacks from
|
||||
// higher kinded types, as good a golang allows use to do this
|
||||
|
||||
func MonadMap[GEA ~func(E) HKTA, GEB ~func(E) HKTB, E, A, B, HKTA, HKTB any](fmap func(HKTA, func(A) B) HKTB, fa GEA, f func(A) B) GEB {
|
||||
return R.MonadMap[GEA, GEB](fa, F.Bind2nd(fmap, f))
|
||||
}
|
||||
|
||||
func MonadChain[GEA ~func(E) HKTA, GEB ~func(E) HKTB, A, E, HKTA, HKTB any](fchain func(HKTA, func(A) HKTB) HKTB, ma GEA, f func(A) GEB) GEB {
|
||||
return R.MakeReader(func(r E) HKTB {
|
||||
return fchain(ma(r), func(a A) HKTB {
|
||||
return f(a)(r)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func MonadOf[GEA ~func(E) HKTA, E, A, HKTA any](fof func(A) HKTA, a A) GEA {
|
||||
return R.MakeReader(func(_ E) HKTA {
|
||||
return fof(a)
|
||||
})
|
||||
}
|
||||
|
||||
// HKTFAB = HKT[func(A)B]
|
||||
func MonadAp[GEA ~func(E) HKTA, GEB ~func(E) HKTB, GEFAB ~func(E) HKTFAB, E, A, HKTA, HKTB, HKTFAB any](fap func(HKTFAB, HKTA) HKTB, fab GEFAB, fa GEA) GEB {
|
||||
return R.MakeReader(func(r E) HKTB {
|
||||
return fap(fab(r), fa(r))
|
||||
})
|
||||
}
|
||||
|
||||
func MonadFromReader[GA ~func(E) A, GEA ~func(E) HKTA, E, A, HKTA any](
|
||||
fof func(A) HKTA, ma GA) GEA {
|
||||
return R.MakeReader(F.Flow2(ma, fof))
|
||||
}
|
||||
|
||||
func FromReader[GA ~func(E) A, GEA ~func(E) HKTA, E, A, HKTA any](
|
||||
fof func(A) HKTA) func(ma GA) GEA {
|
||||
return F.Bind1st(MonadFromReader[GA, GEA, E, A, HKTA], fof)
|
||||
}
|
@ -2,7 +2,7 @@ package option
|
||||
|
||||
import (
|
||||
F "github.com/ibm/fp-go/function"
|
||||
Apply "github.com/ibm/fp-go/internal/apply"
|
||||
"github.com/ibm/fp-go/internal/apply"
|
||||
T "github.com/ibm/fp-go/tuple"
|
||||
)
|
||||
|
||||
@ -20,7 +20,7 @@ func Sequence[A, HKTA, HKTOA any](
|
||||
// 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 Option[A]) Option[T.Tuple1[A]] {
|
||||
return Apply.SequenceT1(
|
||||
return apply.SequenceT1(
|
||||
Map[A, T.Tuple1[A]],
|
||||
|
||||
a,
|
||||
@ -28,7 +28,7 @@ func SequenceT1[A any](a Option[A]) Option[T.Tuple1[A]] {
|
||||
}
|
||||
|
||||
func SequenceT2[A, B any](a Option[A], b Option[B]) Option[T.Tuple2[A, B]] {
|
||||
return Apply.SequenceT2(
|
||||
return apply.SequenceT2(
|
||||
Map[A, func(B) T.Tuple2[A, B]],
|
||||
Ap[T.Tuple2[A, B], B],
|
||||
|
||||
@ -37,7 +37,7 @@ func SequenceT2[A, B any](a Option[A], b Option[B]) Option[T.Tuple2[A, B]] {
|
||||
}
|
||||
|
||||
func SequenceT3[A, B, C any](a Option[A], b Option[B], c Option[C]) Option[T.Tuple3[A, B, C]] {
|
||||
return Apply.SequenceT3(
|
||||
return apply.SequenceT3(
|
||||
Map[A, func(B) func(C) T.Tuple3[A, B, C]],
|
||||
Ap[func(C) T.Tuple3[A, B, C], B],
|
||||
Ap[T.Tuple3[A, B, C], C],
|
||||
@ -47,7 +47,7 @@ func SequenceT3[A, B, C any](a Option[A], b Option[B], c Option[C]) Option[T.Tup
|
||||
}
|
||||
|
||||
func SequenceT4[A, B, C, D any](a Option[A], b Option[B], c Option[C], d Option[D]) Option[T.Tuple4[A, B, C, D]] {
|
||||
return Apply.SequenceT4(
|
||||
return apply.SequenceT4(
|
||||
Map[A, func(B) func(C) func(D) T.Tuple4[A, B, C, D]],
|
||||
Ap[func(C) func(D) T.Tuple4[A, B, C, D], B],
|
||||
Ap[func(D) T.Tuple4[A, B, C, D], C],
|
||||
|
15
reader/array.go
Normal file
15
reader/array.go
Normal file
@ -0,0 +1,15 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func TraverseArray[R, A, B any](f func(A) Reader[R, B]) func([]A) Reader[R, []B] {
|
||||
return G.TraverseArray[Reader[R, B], Reader[R, []B], []A](f)
|
||||
}
|
||||
|
||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArray[R, A any](ma []Reader[R, A]) Reader[R, []A] {
|
||||
return G.SequenceArray[Reader[R, A], Reader[R, []A]](ma)
|
||||
}
|
25
reader/array_test.go
Normal file
25
reader/array_test.go
Normal file
@ -0,0 +1,25 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
A "github.com/ibm/fp-go/array"
|
||||
F "github.com/ibm/fp-go/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSequenceArray(t *testing.T) {
|
||||
|
||||
n := 10
|
||||
|
||||
readers := A.MakeBy(n, Of[context.Context, int])
|
||||
exp := A.MakeBy(n, F.Identity[int])
|
||||
|
||||
g := F.Pipe1(
|
||||
readers,
|
||||
SequenceArray[context.Context, int],
|
||||
)
|
||||
|
||||
assert.Equal(t, exp, g(context.Background()))
|
||||
}
|
49
reader/curry.go
Normal file
49
reader/curry.go
Normal file
@ -0,0 +1,49 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a reader with the context as the last parameter, which
|
||||
// is a equivalent to a function returning a reader of that context
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func Curry0[R, A any](f func(R) A) Reader[R, A] {
|
||||
return G.Curry0[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func Curry1[R, T1, A any](f func(R, T1) A) func(T1) Reader[R, A] {
|
||||
return G.Curry1[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func Curry2[R, T1, T2, A any](f func(R, T1, T2) A) func(T1) func(T2) Reader[R, A] {
|
||||
return G.Curry2[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func Curry3[R, T1, T2, T3, A any](f func(R, T1, T2, T3) A) func(T1) func(T2) func(T3) Reader[R, A] {
|
||||
return G.Curry3[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func Curry4[R, T1, T2, T3, T4, A any](f func(R, T1, T2, T3, T4) A) func(T1) func(T2) func(T3) func(T4) Reader[R, A] {
|
||||
return G.Curry4[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func Uncurry0[R, A any](f Reader[R, A]) func(R) A {
|
||||
return G.Uncurry0(f)
|
||||
}
|
||||
|
||||
func Uncurry1[R, T1, A any](f func(T1) Reader[R, A]) func(R, T1) A {
|
||||
return G.Uncurry1(f)
|
||||
}
|
||||
|
||||
func Uncurry2[R, T1, T2, A any](f func(T1) func(T2) Reader[R, A]) func(R, T1, T2) A {
|
||||
return G.Uncurry2(f)
|
||||
}
|
||||
|
||||
func Uncurry3[R, T1, T2, T3, A any](f func(T1) func(T2) func(T3) Reader[R, A]) func(R, T1, T2, T3) A {
|
||||
return G.Uncurry3(f)
|
||||
}
|
||||
|
||||
func Uncurry4[R, T1, T2, T3, T4, A any](f func(T1) func(T2) func(T3) func(T4) Reader[R, A]) func(R, T1, T2, T3, T4) A {
|
||||
return G.Uncurry4(f)
|
||||
}
|
25
reader/from.go
Normal file
25
reader/from.go
Normal file
@ -0,0 +1,25 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
func From0[R, A any](f func(R) A) Reader[R, A] {
|
||||
return G.From0[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func From1[R, T1, A any](f func(R, T1) A) func(T1) Reader[R, A] {
|
||||
return G.From1[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func From2[R, T1, T2, A any](f func(R, T1, T2) A) func(T1, T2) Reader[R, A] {
|
||||
return G.From2[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func From3[R, T1, T2, T3, A any](f func(R, T1, T2, T3) A) func(T1, T2, T3) Reader[R, A] {
|
||||
return G.From3[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func From4[R, T1, T2, T3, T4, A any](f func(R, T1, T2, T3, T4) A) func(T1, T2, T3, T4) Reader[R, A] {
|
||||
return G.From4[Reader[R, A]](f)
|
||||
}
|
31
reader/generic/array.go
Normal file
31
reader/generic/array.go
Normal file
@ -0,0 +1,31 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
F "github.com/ibm/fp-go/function"
|
||||
RA "github.com/ibm/fp-go/internal/array"
|
||||
)
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func MonadTraverseArray[GB ~func(R) B, GBS ~func(R) BBS, AAS ~[]A, BBS ~[]B, R, A, B any](tas AAS, f func(A) GB) GBS {
|
||||
return RA.MonadTraverse[AAS](
|
||||
Of[GBS, R, BBS],
|
||||
Map[GBS, func(R) func(B) BBS, R, BBS, func(B) BBS],
|
||||
Ap[GB, GBS, func(R) func(B) BBS, R, B, BBS],
|
||||
tas, f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func TraverseArray[GB ~func(R) B, GBS ~func(R) BBS, AAS ~[]A, BBS ~[]B, R, A, B any](f func(A) GB) func(AAS) GBS {
|
||||
return RA.Traverse[AAS](
|
||||
Of[GBS, R, BBS],
|
||||
Map[GBS, func(R) func(B) BBS, R, BBS, func(B) BBS],
|
||||
Ap[GB, GBS, func(R) func(B) BBS, R, B, BBS],
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArray[GA ~func(R) A, GAS ~func(R) AAS, AAS ~[]A, GAAS ~[]GA, R, A any](ma GAAS) GAS {
|
||||
return MonadTraverseArray[GA, GAS](ma, F.Identity[GA])
|
||||
}
|
61
reader/generic/curry.go
Normal file
61
reader/generic/curry.go
Normal file
@ -0,0 +1,61 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
F "github.com/ibm/fp-go/function"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a reader with the context as the last parameter, which
|
||||
// is a equivalent to a function returning a reader of that context
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func Curry0[GA ~func(R) A, R, A any](f func(R) A) GA {
|
||||
return MakeReader[GA](f)
|
||||
}
|
||||
|
||||
func Curry1[GA ~func(R) A, R, T1, A any](f func(R, T1) A) func(T1) GA {
|
||||
return F.Curry1(From1[GA](f))
|
||||
}
|
||||
|
||||
func Curry2[GA ~func(R) A, R, T1, T2, A any](f func(R, T1, T2) A) func(T1) func(T2) GA {
|
||||
return F.Curry2(From2[GA](f))
|
||||
}
|
||||
|
||||
func Curry3[GA ~func(R) A, R, T1, T2, T3, A any](f func(R, T1, T2, T3) A) func(T1) func(T2) func(T3) GA {
|
||||
return F.Curry3(From3[GA](f))
|
||||
}
|
||||
|
||||
func Curry4[GA ~func(R) A, R, T1, T2, T3, T4, A any](f func(R, T1, T2, T3, T4) A) func(T1) func(T2) func(T3) func(T4) GA {
|
||||
return F.Curry4(From4[GA](f))
|
||||
}
|
||||
|
||||
func Uncurry0[GA ~func(R) A, R, A any](f GA) func(R) A {
|
||||
return f
|
||||
}
|
||||
|
||||
func Uncurry1[GA ~func(R) A, R, T1, A any](f func(T1) GA) func(R, T1) A {
|
||||
uc := F.Uncurry1(f)
|
||||
return func(r R, t1 T1) A {
|
||||
return uc(t1)(r)
|
||||
}
|
||||
}
|
||||
|
||||
func Uncurry2[GA ~func(R) A, R, T1, T2, A any](f func(T1) func(T2) GA) func(R, T1, T2) A {
|
||||
uc := F.Uncurry2(f)
|
||||
return func(r R, t1 T1, t2 T2) A {
|
||||
return uc(t1, t2)(r)
|
||||
}
|
||||
}
|
||||
|
||||
func Uncurry3[GA ~func(R) A, R, T1, T2, T3, A any](f func(T1) func(T2) func(T3) GA) func(R, T1, T2, T3) A {
|
||||
uc := F.Uncurry3(f)
|
||||
return func(r R, t1 T1, t2 T2, t3 T3) A {
|
||||
return uc(t1, t2, t3)(r)
|
||||
}
|
||||
}
|
||||
|
||||
func Uncurry4[GA ~func(R) A, R, T1, T2, T3, T4, A any](f func(T1) func(T2) func(T3) func(T4) GA) func(R, T1, T2, T3, T4) A {
|
||||
uc := F.Uncurry4(f)
|
||||
return func(r R, t1 T1, t2 T2, t3 T3, t4 T4) A {
|
||||
return uc(t1, t2, t3, t4)(r)
|
||||
}
|
||||
}
|
41
reader/generic/from.go
Normal file
41
reader/generic/from.go
Normal file
@ -0,0 +1,41 @@
|
||||
package generic
|
||||
|
||||
// these functions convert a golang function with the context as the first parameter into a reader with the context as the last parameter, which
|
||||
// is a equivalent to a function returning a reader of that context
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func From0[GA ~func(R) A, R, A any](f func(R) A) GA {
|
||||
return MakeReader[GA](f)
|
||||
}
|
||||
|
||||
func From1[GA ~func(R) A, R, T1, A any](f func(R, T1) A) func(T1) GA {
|
||||
return func(t1 T1) GA {
|
||||
return MakeReader[GA](func(r R) A {
|
||||
return f(r, t1)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func From2[GA ~func(R) A, R, T1, T2, A any](f func(R, T1, T2) A) func(T1, T2) GA {
|
||||
return func(t1 T1, t2 T2) GA {
|
||||
return MakeReader[GA](func(r R) A {
|
||||
return f(r, t1, t2)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func From3[GA ~func(R) A, R, T1, T2, T3, A any](f func(R, T1, T2, T3) A) func(T1, T2, T3) GA {
|
||||
return func(t1 T1, t2 T2, t3 T3) GA {
|
||||
return MakeReader[GA](func(r R) A {
|
||||
return f(r, t1, t2, t3)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func From4[GA ~func(R) A, R, T1, T2, T3, T4, A any](f func(R, T1, T2, T3, T4) A) func(T1, T2, T3, T4) GA {
|
||||
return func(t1 T1, t2 T2, t3 T3, t4 T4) GA {
|
||||
return MakeReader[GA](func(r R) A {
|
||||
return f(r, t1, t2, t3, t4)
|
||||
})
|
||||
}
|
||||
}
|
107
reader/generic/reader.go
Normal file
107
reader/generic/reader.go
Normal file
@ -0,0 +1,107 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
F "github.com/ibm/fp-go/function"
|
||||
I "github.com/ibm/fp-go/identity/generic"
|
||||
T "github.com/ibm/fp-go/tuple"
|
||||
)
|
||||
|
||||
// Reader[R, A] = func(R) A
|
||||
|
||||
// MakeReader creates a reader, i.e. a method that accepts a context and that returns a value
|
||||
func MakeReader[GA ~func(R) A, R, A any](r GA) GA {
|
||||
return r
|
||||
}
|
||||
|
||||
// Ask reads the current context
|
||||
func Ask[GR ~func(R) R, R any]() GR {
|
||||
return MakeReader(F.Identity[R])
|
||||
}
|
||||
|
||||
// Asks projects a value from the global context in a Reader
|
||||
func Asks[GA ~func(R) A, R, A any](f GA) GA {
|
||||
return MakeReader(f)
|
||||
}
|
||||
|
||||
func AsksReader[GA ~func(R) A, R, A any](f func(R) GA) GA {
|
||||
return MakeReader(func(r R) A {
|
||||
return f(r)(r)
|
||||
})
|
||||
}
|
||||
|
||||
func MonadMap[GA ~func(E) A, GB ~func(E) B, E, A, B any](fa GA, f func(A) B) GB {
|
||||
return MakeReader(F.Flow2(fa, f))
|
||||
}
|
||||
|
||||
// Map can be used to turn functions `func(A)B` into functions `(fa F[A])F[B]` whose argument and return types
|
||||
// use the type constructor `F` to represent some computational context.
|
||||
func Map[GA ~func(E) A, GB ~func(E) B, E, A, B any](f func(A) B) func(GA) GB {
|
||||
return F.Bind2nd(MonadMap[GA, GB, E, A, B], f)
|
||||
}
|
||||
|
||||
func MonadAp[GA ~func(R) A, GB ~func(R) B, GAB ~func(R) func(A) B, R, A, B any](fab GAB, fa GA) GB {
|
||||
return MakeReader(func(r R) B {
|
||||
return fab(r)(fa(r))
|
||||
})
|
||||
}
|
||||
|
||||
// Ap applies a function to an argument under a type constructor.
|
||||
func Ap[GA ~func(R) A, GB ~func(R) B, GAB ~func(R) func(A) B, R, A, B any](fa GA) func(GAB) GB {
|
||||
return F.Bind2nd(MonadAp[GA, GB, GAB, R, A, B], fa)
|
||||
}
|
||||
|
||||
func Of[GA ~func(R) A, R, A any](a A) GA {
|
||||
return F.Constant1[R](a)
|
||||
}
|
||||
|
||||
func MonadChain[GA ~func(R) A, GB ~func(R) B, R, A, B any](ma GA, f func(A) GB) GB {
|
||||
return MakeReader(func(r R) B {
|
||||
return f(ma(r))(r)
|
||||
})
|
||||
}
|
||||
|
||||
// Chain composes computations in sequence, using the return value of one computation to determine the next computation.
|
||||
func Chain[GA ~func(R) A, GB ~func(R) B, R, A, B any](f func(A) GB) func(GA) GB {
|
||||
return F.Bind2nd(MonadChain[GA, GB, R, A, B], f)
|
||||
}
|
||||
|
||||
func Flatten[GA ~func(R) A, GGA ~func(R) GA, R, A any](mma GGA) GA {
|
||||
return MonadChain(mma, F.Identity[GA])
|
||||
}
|
||||
|
||||
func Compose[AB ~func(A) B, BC ~func(B) C, AC ~func(A) C, A, B, C any](ab AB) func(BC) AC {
|
||||
return func(bc BC) AC {
|
||||
return F.Flow2(ab, bc)
|
||||
}
|
||||
}
|
||||
|
||||
func First[GAB ~func(A) B, GABC ~func(T.Tuple2[A, C]) T.Tuple2[B, C], A, B, C any](pab GAB) GABC {
|
||||
return MakeReader(func(tac T.Tuple2[A, C]) T.Tuple2[B, C] {
|
||||
return T.MakeTuple2(pab(tac.F1), tac.F2)
|
||||
})
|
||||
}
|
||||
|
||||
func Second[GBC ~func(B) C, GABC ~func(T.Tuple2[A, B]) T.Tuple2[A, C], A, B, C any](pbc GBC) GABC {
|
||||
return MakeReader(func(tab T.Tuple2[A, B]) T.Tuple2[A, C] {
|
||||
return T.MakeTuple2(tab.F1, pbc(tab.F2))
|
||||
})
|
||||
}
|
||||
|
||||
func Promap[GA ~func(E) A, GB ~func(D) B, E, A, D, B any](f func(D) E, g func(A) B) func(GA) GB {
|
||||
return func(fea GA) GB {
|
||||
return MakeReader(F.Flow3(f, fea, g))
|
||||
}
|
||||
}
|
||||
|
||||
// Local changes the value of the local context during the execution of the action `ma` (similar to `Contravariant`'s
|
||||
// `contramap`).
|
||||
func Local[GA1 ~func(R1) A, GA2 ~func(R2) A, R2, R1, A any](f func(R2) R1) func(GA1) GA2 {
|
||||
return func(r1 GA1) GA2 {
|
||||
return F.Flow2(f, r1)
|
||||
}
|
||||
}
|
||||
|
||||
// Read applies a context to a reader to obtain its value
|
||||
func Read[GA ~func(E) A, E, A any](e E) func(GA) A {
|
||||
return I.Ap[GA](e)
|
||||
}
|
46
reader/generic/sequence.go
Normal file
46
reader/generic/sequence.go
Normal file
@ -0,0 +1,46 @@
|
||||
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(R) A, GTA ~func(R) T.Tuple1[A], R, A any](a GA) GTA {
|
||||
return apply.SequenceT1(
|
||||
Map[GA, GTA, R, A, T.Tuple1[A]],
|
||||
|
||||
a,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceT2[GA ~func(R) A, GB ~func(R) B, GTAB ~func(R) T.Tuple2[A, B], R, A, B any](a GA, b GB) GTAB {
|
||||
return apply.SequenceT2(
|
||||
Map[GA, func(R) func(B) T.Tuple2[A, B], R, A, func(B) T.Tuple2[A, B]],
|
||||
Ap[GB, GTAB, func(R) func(B) T.Tuple2[A, B], R, B, T.Tuple2[A, B]],
|
||||
|
||||
a, b,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceT3[GA ~func(R) A, GB ~func(R) B, GC ~func(R) C, GTABC ~func(R) T.Tuple3[A, B, C], R, A, B, C any](a GA, b GB, c GC) GTABC {
|
||||
return apply.SequenceT3(
|
||||
Map[GA, func(R) func(B) func(C) T.Tuple3[A, B, C], R, A, func(B) func(C) T.Tuple3[A, B, C]],
|
||||
Ap[GB, func(R) func(C) T.Tuple3[A, B, C], func(R) func(B) func(C) T.Tuple3[A, B, C], R, B, func(C) T.Tuple3[A, B, C]],
|
||||
Ap[GC, GTABC, func(R) func(C) T.Tuple3[A, B, C], R, C, T.Tuple3[A, B, C]],
|
||||
|
||||
a, b, c,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceT4[GA ~func(R) A, GB ~func(R) B, GC ~func(R) C, GD ~func(R) D, GTABCD ~func(R) T.Tuple4[A, B, C, D], R, A, B, C, D any](a GA, b GB, c GC, d GD) GTABCD {
|
||||
return apply.SequenceT4(
|
||||
Map[GA, func(R) func(B) func(C) func(D) T.Tuple4[A, B, C, D], R, A, func(B) func(C) func(D) T.Tuple4[A, B, C, D]],
|
||||
Ap[GB, func(R) func(C) func(D) T.Tuple4[A, B, C, D], func(R) func(B) func(C) func(D) T.Tuple4[A, B, C, D], R, B, func(C) func(D) T.Tuple4[A, B, C, D]],
|
||||
Ap[GC, func(R) func(D) T.Tuple4[A, B, C, D], func(R) func(C) func(D) T.Tuple4[A, B, C, D], R, C, func(D) T.Tuple4[A, B, C, D]],
|
||||
Ap[GD, GTABCD, func(R) func(D) T.Tuple4[A, B, C, D], R, D, T.Tuple4[A, B, C, D]],
|
||||
|
||||
a, b, c, d,
|
||||
)
|
||||
}
|
92
reader/reader.go
Normal file
92
reader/reader.go
Normal file
@ -0,0 +1,92 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/reader/generic"
|
||||
T "github.com/ibm/fp-go/tuple"
|
||||
)
|
||||
|
||||
// The purpose of the `Reader` monad is to avoid threading arguments through multiple functions in order to only get them where they are needed.
|
||||
// The first template argument `R` is the the context to read from, the second argument `A` is the return value of the monad
|
||||
type Reader[R, A any] func(R) A
|
||||
|
||||
// MakeReader creates a reader, i.e. a method that accepts a context and that returns a value
|
||||
func MakeReader[R, A any](r Reader[R, A]) Reader[R, A] {
|
||||
return G.MakeReader(r)
|
||||
}
|
||||
|
||||
// Ask reads the current context
|
||||
func Ask[R any]() Reader[R, R] {
|
||||
return G.Ask[Reader[R, R]]()
|
||||
}
|
||||
|
||||
// Asks projects a value from the global context in a Reader
|
||||
func Asks[R, A any](f Reader[R, A]) Reader[R, A] {
|
||||
return G.Asks(f)
|
||||
}
|
||||
|
||||
func AsksReader[R, A any](f func(R) Reader[R, A]) Reader[R, A] {
|
||||
return G.AsksReader(f)
|
||||
}
|
||||
|
||||
func MonadMap[E, A, B any](fa Reader[E, A], f func(A) B) Reader[E, B] {
|
||||
return G.MonadMap[Reader[E, A], Reader[E, B]](fa, f)
|
||||
}
|
||||
|
||||
// Map can be used to turn functions `func(A)B` into functions `(fa F[A])F[B]` whose argument and return types
|
||||
// use the type constructor `F` to represent some computational context.
|
||||
func Map[E, A, B any](f func(A) B) func(Reader[E, A]) Reader[E, B] {
|
||||
return G.Map[Reader[E, A], Reader[E, B]](f)
|
||||
}
|
||||
|
||||
func MonadAp[B, R, A any](fab Reader[R, func(A) B], fa Reader[R, A]) Reader[R, B] {
|
||||
return G.MonadAp[Reader[R, A], Reader[R, B]](fab, fa)
|
||||
}
|
||||
|
||||
// Ap applies a function to an argument under a type constructor.
|
||||
func Ap[B, R, A any](fa Reader[R, A]) func(Reader[R, func(A) B]) Reader[R, B] {
|
||||
return G.Ap[Reader[R, A], Reader[R, B], Reader[R, func(A) B]](fa)
|
||||
}
|
||||
|
||||
func Of[R, A any](a A) Reader[R, A] {
|
||||
return G.Of[Reader[R, A]](a)
|
||||
}
|
||||
|
||||
func MonadChain[R, A, B any](ma Reader[R, A], f func(A) Reader[R, B]) Reader[R, B] {
|
||||
return G.MonadChain(ma, f)
|
||||
}
|
||||
|
||||
// Chain composes computations in sequence, using the return value of one computation to determine the next computation.
|
||||
func Chain[R, A, B any](f func(A) Reader[R, B]) func(Reader[R, A]) Reader[R, B] {
|
||||
return G.Chain[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func Flatten[R, A any](mma func(R) Reader[R, A]) Reader[R, A] {
|
||||
return G.Flatten(mma)
|
||||
}
|
||||
|
||||
func Compose[R, B, C any](ab Reader[R, B]) func(Reader[B, C]) Reader[R, C] {
|
||||
return G.Compose[Reader[R, B], Reader[B, C], Reader[R, C]](ab)
|
||||
}
|
||||
|
||||
func First[A, B, C any](pab Reader[A, B]) Reader[T.Tuple2[A, C], T.Tuple2[B, C]] {
|
||||
return G.First[Reader[A, B], Reader[T.Tuple2[A, C], T.Tuple2[B, C]]](pab)
|
||||
}
|
||||
|
||||
func Second[A, B, C any](pbc Reader[B, C]) Reader[T.Tuple2[A, B], T.Tuple2[A, C]] {
|
||||
return G.Second[Reader[B, C], Reader[T.Tuple2[A, B], T.Tuple2[A, C]]](pbc)
|
||||
}
|
||||
|
||||
func Promap[E, A, D, B any](f func(D) E, g func(A) B) func(Reader[E, A]) Reader[D, B] {
|
||||
return G.Promap[Reader[E, A], Reader[D, B]](f, g)
|
||||
}
|
||||
|
||||
// Local changes the value of the local context during the execution of the action `ma` (similar to `Contravariant`'s
|
||||
// `contramap`).
|
||||
func Local[R2, R1, A any](f func(R2) R1) func(Reader[R1, A]) Reader[R2, A] {
|
||||
return G.Local[Reader[R1, A], Reader[R2, A]](f)
|
||||
}
|
||||
|
||||
// Read applies a context to a reader to obtain its value
|
||||
func Read[E, A any](e E) func(Reader[E, A]) A {
|
||||
return G.Read[Reader[E, A]](e)
|
||||
}
|
19
reader/reader_test.go
Normal file
19
reader/reader_test.go
Normal file
@ -0,0 +1,19 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
F "github.com/ibm/fp-go/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/ibm/fp-go/internal/utils"
|
||||
)
|
||||
|
||||
func TestMap(t *testing.T) {
|
||||
|
||||
assert.Equal(t, 2, F.Pipe1(Of[string](1), Map[string](utils.Double))(""))
|
||||
}
|
||||
|
||||
func TestAp(t *testing.T) {
|
||||
assert.Equal(t, 2, F.Pipe1(Of[int](utils.Double), Ap[int, int, int](Of[int](1)))(0))
|
||||
}
|
25
reader/semigroup.go
Normal file
25
reader/semigroup.go
Normal file
@ -0,0 +1,25 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
M "github.com/ibm/fp-go/monoid"
|
||||
S "github.com/ibm/fp-go/semigroup"
|
||||
)
|
||||
|
||||
func ApplySemigroup[R, A any](
|
||||
_map func(func(R) A, func(A) func(A) A) func(R, func(A) A),
|
||||
_ap func(func(R, func(A) A), func(R) A) func(R) A,
|
||||
|
||||
s S.Semigroup[A],
|
||||
) S.Semigroup[func(R) A] {
|
||||
return S.ApplySemigroup(_map, _ap, s)
|
||||
}
|
||||
|
||||
func ApplicativeMonoid[R, A any](
|
||||
_of func(A) func(R) A,
|
||||
_map func(func(R) A, func(A) func(A) A) func(R, func(A) A),
|
||||
_ap func(func(R, func(A) A), func(R) A) func(R) A,
|
||||
|
||||
m M.Monoid[A],
|
||||
) M.Monoid[func(R) A] {
|
||||
return M.ApplicativeMonoid(_of, _map, _ap, m)
|
||||
}
|
24
reader/sequence.go
Normal file
24
reader/sequence.go
Normal file
@ -0,0 +1,24 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/reader/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[R, A any](a Reader[R, A]) Reader[R, T.Tuple1[A]] {
|
||||
return G.SequenceT1[Reader[R, A], Reader[R, T.Tuple1[A]]](a)
|
||||
}
|
||||
|
||||
func SequenceT2[R, A, B any](a Reader[R, A], b Reader[R, B]) Reader[R, T.Tuple2[A, B]] {
|
||||
return G.SequenceT2[Reader[R, A], Reader[R, B], Reader[R, T.Tuple2[A, B]]](a, b)
|
||||
}
|
||||
|
||||
func SequenceT3[R, A, B, C any](a Reader[R, A], b Reader[R, B], c Reader[R, C]) Reader[R, T.Tuple3[A, B, C]] {
|
||||
return G.SequenceT3[Reader[R, A], Reader[R, B], Reader[R, C], Reader[R, T.Tuple3[A, B, C]]](a, b, c)
|
||||
}
|
||||
|
||||
func SequenceT4[R, A, B, C, D any](a Reader[R, A], b Reader[R, B], c Reader[R, C], d Reader[R, D]) Reader[R, T.Tuple4[A, B, C, D]] {
|
||||
return G.SequenceT4[Reader[R, A], Reader[R, B], Reader[R, C], Reader[R, D], Reader[R, T.Tuple4[A, B, C, D]]](a, b, c, d)
|
||||
}
|
15
readereither/array.go
Normal file
15
readereither/array.go
Normal file
@ -0,0 +1,15 @@
|
||||
package readereither
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/readereither/generic"
|
||||
)
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func TraverseArray[E, L, A, B any](f func(A) ReaderEither[E, L, B]) func([]A) ReaderEither[E, L, []B] {
|
||||
return G.TraverseArray[ReaderEither[E, L, B], ReaderEither[E, L, []B], []A](f)
|
||||
}
|
||||
|
||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArray[E, L, A any](ma []ReaderEither[E, L, A]) ReaderEither[E, L, []A] {
|
||||
return G.SequenceArray[ReaderEither[E, L, A], ReaderEither[E, L, []A]](ma)
|
||||
}
|
26
readereither/array_test.go
Normal file
26
readereither/array_test.go
Normal file
@ -0,0 +1,26 @@
|
||||
package readereither
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
A "github.com/ibm/fp-go/array"
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
F "github.com/ibm/fp-go/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSequenceArray(t *testing.T) {
|
||||
|
||||
n := 10
|
||||
|
||||
readers := A.MakeBy(n, Of[context.Context, error, int])
|
||||
exp := ET.Of[error](A.MakeBy(n, F.Identity[int]))
|
||||
|
||||
g := F.Pipe1(
|
||||
readers,
|
||||
SequenceArray[context.Context, error, int],
|
||||
)
|
||||
|
||||
assert.Equal(t, exp, g(context.Background()))
|
||||
}
|
36
readereither/curry.go
Normal file
36
readereither/curry.go
Normal file
@ -0,0 +1,36 @@
|
||||
package readereither
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/readereither/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func Curry0[R, A any](f func(R) (A, error)) ReaderEither[R, error, A] {
|
||||
return G.Curry0[ReaderEither[R, error, A]](f)
|
||||
}
|
||||
|
||||
func Curry1[R, T1, A any](f func(R, T1) (A, error)) func(T1) ReaderEither[R, error, A] {
|
||||
return G.Curry1[ReaderEither[R, error, A]](f)
|
||||
}
|
||||
|
||||
func Curry2[R, T1, T2, A any](f func(R, T1, T2) (A, error)) func(T1) func(T2) ReaderEither[R, error, A] {
|
||||
return G.Curry2[ReaderEither[R, error, A]](f)
|
||||
}
|
||||
|
||||
func Curry3[R, T1, T2, T3, A any](f func(R, T1, T2, T3) (A, error)) func(T1) func(T2) func(T3) ReaderEither[R, error, A] {
|
||||
return G.Curry3[ReaderEither[R, error, A]](f)
|
||||
}
|
||||
|
||||
func Uncurry1[R, T1, A any](f func(T1) ReaderEither[R, error, A]) func(R, T1) (A, error) {
|
||||
return G.Uncurry1(f)
|
||||
}
|
||||
|
||||
func Uncurry2[R, T1, T2, A any](f func(T1) func(T2) ReaderEither[R, error, A]) func(R, T1, T2) (A, error) {
|
||||
return G.Uncurry2(f)
|
||||
}
|
||||
|
||||
func Uncurry3[R, T1, T2, T3, A any](f func(T1) func(T2) func(T3) ReaderEither[R, error, A]) func(R, T1, T2, T3) (A, error) {
|
||||
return G.Uncurry3(f)
|
||||
}
|
24
readereither/from.go
Normal file
24
readereither/from.go
Normal file
@ -0,0 +1,24 @@
|
||||
package readereither
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/readereither/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func From0[R, A any](f func(R) (A, error)) ReaderEither[R, error, A] {
|
||||
return G.From0[ReaderEither[R, error, A]](f)
|
||||
}
|
||||
|
||||
func From1[R, T1, A any](f func(R, T1) (A, error)) func(T1) ReaderEither[R, error, A] {
|
||||
return G.From1[ReaderEither[R, error, A]](f)
|
||||
}
|
||||
|
||||
func From2[R, T1, T2, A any](f func(R, T1, T2) (A, error)) func(T1, T2) ReaderEither[R, error, A] {
|
||||
return G.From2[ReaderEither[R, error, A]](f)
|
||||
}
|
||||
|
||||
func From3[R, T1, T2, T3, A any](f func(R, T1, T2, T3) (A, error)) func(T1, T2, T3) ReaderEither[R, error, A] {
|
||||
return G.From3[ReaderEither[R, error, A]](f)
|
||||
}
|
34
readereither/generic/array.go
Normal file
34
readereither/generic/array.go
Normal file
@ -0,0 +1,34 @@
|
||||
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"
|
||||
)
|
||||
|
||||
// MonadTraverseArray transforms an array
|
||||
func MonadTraverseArray[GB ~func(E) ET.Either[L, B], GBS ~func(E) ET.Either[L, BBS], AAS ~[]A, BBS ~[]B, L, E, A, B any](ma AAS, f func(A) GB) GBS {
|
||||
return RA.MonadTraverse[AAS](
|
||||
Of[GBS, L, E, BBS],
|
||||
Map[GBS, func(E) ET.Either[L, func(B) BBS], L, E, BBS, func(B) BBS],
|
||||
Ap[GB, GBS, func(E) ET.Either[L, func(B) BBS], L, E, B, BBS],
|
||||
|
||||
ma, f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func TraverseArray[GB ~func(E) ET.Either[L, B], GBS ~func(E) ET.Either[L, BBS], AAS ~[]A, BBS ~[]B, L, E, A, B any](f func(A) GB) func(AAS) GBS {
|
||||
return RA.Traverse[AAS](
|
||||
Of[GBS, L, E, BBS],
|
||||
Map[GBS, func(E) ET.Either[L, func(B) BBS], L, E, BBS, func(B) BBS],
|
||||
Ap[GB, GBS, func(E) ET.Either[L, func(B) BBS], L, E, B, BBS],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArray[GA ~func(E) ET.Either[L, A], GAS ~func(E) ET.Either[L, AAS], AAS ~[]A, GAAS ~[]GA, L, E, A any](ma GAAS) GAS {
|
||||
return MonadTraverseArray[GA, GAS](ma, F.Identity[GA])
|
||||
}
|
37
readereither/generic/curry.go
Normal file
37
readereither/generic/curry.go
Normal file
@ -0,0 +1,37 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
G "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func Curry0[GEA ~func(R) ET.Either[error, A], R, A any](f func(R) (A, error)) GEA {
|
||||
return G.Curry0[GEA](ET.Eitherize1(f))
|
||||
}
|
||||
|
||||
func Curry1[GEA ~func(R) ET.Either[error, A], R, T1, A any](f func(R, T1) (A, error)) func(T1) GEA {
|
||||
return G.Curry1[GEA](ET.Eitherize2(f))
|
||||
}
|
||||
|
||||
func Curry2[GEA ~func(R) ET.Either[error, A], R, T1, T2, A any](f func(R, T1, T2) (A, error)) func(T1) func(T2) GEA {
|
||||
return G.Curry2[GEA](ET.Eitherize3(f))
|
||||
}
|
||||
|
||||
func Curry3[GEA ~func(R) ET.Either[error, A], R, T1, T2, T3, A any](f func(R, T1, T2, T3) (A, error)) func(T1) func(T2) func(T3) GEA {
|
||||
return G.Curry3[GEA](ET.Eitherize4(f))
|
||||
}
|
||||
|
||||
func Uncurry1[GEA ~func(R) ET.Either[error, A], R, T1, A any](f func(T1) GEA) func(R, T1) (A, error) {
|
||||
return ET.Uneitherize2(G.Uncurry1(f))
|
||||
}
|
||||
|
||||
func Uncurry2[GEA ~func(R) ET.Either[error, A], R, T1, T2, A any](f func(T1) func(T2) GEA) func(R, T1, T2) (A, error) {
|
||||
return ET.Uneitherize3(G.Uncurry2(f))
|
||||
}
|
||||
|
||||
func Uncurry3[GEA ~func(R) ET.Either[error, A], R, T1, T2, T3, A any](f func(T1) func(T2) func(T3) GEA) func(R, T1, T2, T3) (A, error) {
|
||||
return ET.Uneitherize4(G.Uncurry3(f))
|
||||
}
|
25
readereither/generic/from.go
Normal file
25
readereither/generic/from.go
Normal file
@ -0,0 +1,25 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
G "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
// these functions From a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func From0[GEA ~func(R) ET.Either[error, A], R, A any](f func(R) (A, error)) GEA {
|
||||
return G.From0[GEA](ET.Eitherize1(f))
|
||||
}
|
||||
|
||||
func From1[GEA ~func(R) ET.Either[error, A], R, T1, A any](f func(R, T1) (A, error)) func(T1) GEA {
|
||||
return G.From1[GEA](ET.Eitherize2(f))
|
||||
}
|
||||
|
||||
func From2[GEA ~func(R) ET.Either[error, A], R, T1, T2, A any](f func(R, T1, T2) (A, error)) func(T1, T2) GEA {
|
||||
return G.From2[GEA](ET.Eitherize3(f))
|
||||
}
|
||||
|
||||
func From3[GEA ~func(R) ET.Either[error, A], R, T1, T2, T3, A any](f func(R, T1, T2, T3) (A, error)) func(T1, T2, T3) GEA {
|
||||
return G.From3[GEA](ET.Eitherize4(f))
|
||||
}
|
142
readereither/generic/reader.go
Normal file
142
readereither/generic/reader.go
Normal file
@ -0,0 +1,142 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
F "github.com/ibm/fp-go/function"
|
||||
"github.com/ibm/fp-go/internal/eithert"
|
||||
FE "github.com/ibm/fp-go/internal/fromeither"
|
||||
FR "github.com/ibm/fp-go/internal/fromreader"
|
||||
"github.com/ibm/fp-go/internal/readert"
|
||||
O "github.com/ibm/fp-go/option"
|
||||
R "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
func MakeReaderEither[GEA ~func(E) ET.Either[L, A], L, E, A any](f func(E) ET.Either[L, A]) GEA {
|
||||
return f
|
||||
}
|
||||
|
||||
func FromEither[GEA ~func(E) ET.Either[L, A], L, E, A any](e ET.Either[L, A]) GEA {
|
||||
return R.Of[GEA](e)
|
||||
}
|
||||
|
||||
func RightReader[GA ~func(E) A, GEA ~func(E) ET.Either[L, A], L, E, A any](r GA) GEA {
|
||||
return eithert.RightF(R.MonadMap[GA, GEA, E, A, ET.Either[L, A]], r)
|
||||
}
|
||||
|
||||
func LeftReader[GL ~func(E) L, GEA ~func(E) ET.Either[L, A], L, E, A any](l GL) GEA {
|
||||
return eithert.LeftF(R.MonadMap[GL, GEA, E, L, ET.Either[L, A]], l)
|
||||
}
|
||||
|
||||
func Left[GEA ~func(E) ET.Either[L, A], L, E, A any](l L) GEA {
|
||||
return eithert.Left(R.Of[GEA, E, ET.Either[L, A]], l)
|
||||
}
|
||||
|
||||
func Right[GEA ~func(E) ET.Either[L, A], L, E, A any](r A) GEA {
|
||||
return eithert.Right(R.Of[GEA, E, ET.Either[L, A]], r)
|
||||
}
|
||||
|
||||
func FromReader[GA ~func(E) A, GEA ~func(E) ET.Either[L, A], L, E, A any](r GA) GEA {
|
||||
return RightReader[GA, GEA](r)
|
||||
}
|
||||
|
||||
func MonadMap[GEA ~func(E) ET.Either[L, A], GEB ~func(E) ET.Either[L, B], L, E, A, B any](fa GEA, f func(A) B) GEB {
|
||||
return readert.MonadMap[GEA, GEB](ET.MonadMap[L, A, B], fa, f)
|
||||
}
|
||||
|
||||
func Map[GEA ~func(E) ET.Either[L, A], GEB ~func(E) ET.Either[L, B], L, E, A, B any](f func(A) B) func(GEA) GEB {
|
||||
return F.Bind2nd(MonadMap[GEA, GEB, L, E, A, B], f)
|
||||
}
|
||||
|
||||
func MonadChain[GEA ~func(E) ET.Either[L, A], GEB ~func(E) ET.Either[L, B], L, E, A, B any](ma GEA, f func(A) GEB) GEB {
|
||||
return readert.MonadChain(ET.MonadChain[L, A, B], ma, f)
|
||||
}
|
||||
|
||||
func Chain[GEA ~func(E) ET.Either[L, A], GEB ~func(E) ET.Either[L, B], L, E, A, B any](f func(A) GEB) func(GEA) GEB {
|
||||
return F.Bind2nd(MonadChain[GEA, GEB, L, E, A, B], f)
|
||||
}
|
||||
|
||||
func Of[GEA ~func(E) ET.Either[L, A], L, E, A any](a A) GEA {
|
||||
return readert.MonadOf[GEA](ET.Of[L, A], a)
|
||||
}
|
||||
|
||||
func MonadAp[GEA ~func(E) ET.Either[L, A], GEB ~func(E) ET.Either[L, B], GEFAB ~func(E) ET.Either[L, func(A) B], L, E, A, B any](fab GEFAB, fa GEA) GEB {
|
||||
return readert.MonadAp[GEA, GEB, GEFAB, E, A](ET.MonadAp[B, L, A], fab, fa)
|
||||
}
|
||||
|
||||
func Ap[GEA ~func(E) ET.Either[L, A], GEB ~func(E) ET.Either[L, B], GEFAB ~func(E) ET.Either[L, func(A) B], L, E, A, B any](fa GEA) func(GEFAB) GEB {
|
||||
return F.Bind2nd(MonadAp[GEA, GEB, GEFAB, L, E, A, B], fa)
|
||||
}
|
||||
|
||||
func FromPredicate[GEA ~func(E) ET.Either[L, A], L, E, A any](pred func(A) bool, onFalse func(A) L) func(A) GEA {
|
||||
return FE.FromPredicate(FromEither[GEA, L, E, A], pred, onFalse)
|
||||
}
|
||||
|
||||
func Fold[GEA ~func(E) ET.Either[L, A], GB ~func(E) B, E, L, A, B any](onLeft func(L) GB, onRight func(A) GB) func(GEA) GB {
|
||||
return eithert.MatchE(R.MonadChain[GEA, GB, E, ET.Either[L, A], B], onLeft, onRight)
|
||||
}
|
||||
|
||||
func GetOrElse[GEA ~func(E) ET.Either[L, A], GA ~func(E) A, E, L, A any](onLeft func(L) GA) func(GEA) GA {
|
||||
return eithert.GetOrElse(R.MonadChain[GEA, GA, E, ET.Either[L, A], A], R.Of[GA, E, A], onLeft)
|
||||
}
|
||||
|
||||
func OrElse[GEA1 ~func(E) ET.Either[L1, A], GEA2 ~func(E) ET.Either[L2, A], E, L1, A, L2 any](onLeft func(L1) GEA2) func(GEA1) GEA2 {
|
||||
return eithert.OrElse(R.MonadChain[GEA1, GEA2, E, ET.Either[L1, A], ET.Either[L2, A]], R.Of[GEA2, E, ET.Either[L2, A]], onLeft)
|
||||
}
|
||||
|
||||
func OrLeft[GEA1 ~func(E) ET.Either[L1, A], GEA2 ~func(E) ET.Either[L2, A], GE2 ~func(E) L2, L1, E, L2, A any](onLeft func(L1) GE2) func(GEA1) GEA2 {
|
||||
return eithert.OrLeft(
|
||||
R.MonadChain[GEA1, GEA2, E, ET.Either[L1, A], ET.Either[L2, A]],
|
||||
R.MonadMap[GE2, GEA2, E, L2, ET.Either[L2, A]],
|
||||
R.Of[GEA2, E, ET.Either[L2, A]],
|
||||
onLeft,
|
||||
)
|
||||
}
|
||||
|
||||
func Ask[GEE ~func(E) ET.Either[L, E], E, L any]() GEE {
|
||||
return FR.Ask(FromReader[func(E) E, GEE, L, E, E])()
|
||||
}
|
||||
|
||||
func Asks[GA ~func(E) A, GEA ~func(E) ET.Either[L, A], E, L, A any](r GA) GEA {
|
||||
return FR.Asks(FromReader[GA, GEA, L, E, A])(r)
|
||||
}
|
||||
|
||||
func MonadChainEitherK[GEA ~func(E) ET.Either[L, A], GEB ~func(E) ET.Either[L, B], L, E, A, B any](ma GEA, f func(A) ET.Either[L, B]) GEB {
|
||||
return FE.MonadChainEitherK(
|
||||
MonadChain[GEA, GEB, L, E, A, B],
|
||||
FromEither[GEB, L, E, B],
|
||||
ma,
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func ChainEitherK[GEA ~func(E) ET.Either[L, A], GEB ~func(E) ET.Either[L, B], L, E, A, B any](f func(A) ET.Either[L, B]) func(ma GEA) GEB {
|
||||
return F.Bind2nd(MonadChainEitherK[GEA, GEB, L, E, A, B], f)
|
||||
}
|
||||
|
||||
func ChainOptionK[GEA ~func(E) ET.Either[L, A], GEB ~func(E) ET.Either[L, B], L, E, A, B any](onNone func() L) func(func(A) O.Option[B]) func(GEA) GEB {
|
||||
return FE.ChainOptionK(MonadChain[GEA, GEB, L, E, A, B], FromEither[GEB, L, E, B], onNone)
|
||||
}
|
||||
|
||||
func Flatten[GEA ~func(E) ET.Either[L, A], GGA ~func(E) ET.Either[L, GEA], L, E, A any](mma GGA) GEA {
|
||||
return MonadChain(mma, F.Identity[GEA])
|
||||
}
|
||||
|
||||
func MonadBiMap[GA ~func(E) ET.Either[E1, A], GB ~func(E) ET.Either[E2, B], E, E1, E2, A, B any](fa GA, f func(E1) E2, g func(A) B) GB {
|
||||
return eithert.MonadBiMap(R.MonadMap[GA, GB, E, 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(E) ET.Either[E1, A], GB ~func(E) ET.Either[E2, B], E, E1, E2, A, B any](f func(E1) E2, g func(A) B) func(GA) GB {
|
||||
return eithert.BiMap(R.MonadMap[GA, GB, E, ET.Either[E1, A], ET.Either[E2, B]], f, g)
|
||||
}
|
||||
|
||||
// Local changes the value of the local context during the execution of the action `ma` (similar to `Contravariant`'s
|
||||
// `contramap`).
|
||||
func Local[GA1 ~func(R1) ET.Either[E, A], GA2 ~func(R2) ET.Either[E, A], R2, R1, E, A any](f func(R2) R1) func(GA1) GA2 {
|
||||
return R.Local[GA1, GA2](f)
|
||||
}
|
||||
|
||||
// Read applies a context to a reader to obtain its value
|
||||
func Read[GA ~func(E) ET.Either[E1, A], E, E1, A any](e E) func(GA) ET.Either[E1, A] {
|
||||
return R.Read[GA](e)
|
||||
}
|
65
readereither/generic/sequence.go
Normal file
65
readereither/generic/sequence.go
Normal file
@ -0,0 +1,65 @@
|
||||
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(E) ET.Either[L, A],
|
||||
GTA ~func(E) ET.Either[L, T.Tuple1[A]],
|
||||
L, E, A any](a GA) GTA {
|
||||
return apply.SequenceT1(
|
||||
Map[GA, GTA, L, E, A, T.Tuple1[A]],
|
||||
|
||||
a,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceT2[
|
||||
GA ~func(E) ET.Either[L, A],
|
||||
GB ~func(E) ET.Either[L, B],
|
||||
GTAB ~func(E) ET.Either[L, T.Tuple2[A, B]],
|
||||
L, E, A, B any](a GA, b GB) GTAB {
|
||||
return apply.SequenceT2(
|
||||
Map[GA, func(E) ET.Either[L, func(B) T.Tuple2[A, B]], L, E, A, func(B) T.Tuple2[A, B]],
|
||||
Ap[GB, GTAB, func(E) ET.Either[L, func(B) T.Tuple2[A, B]], L, E, B, T.Tuple2[A, B]],
|
||||
|
||||
a, b,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceT3[
|
||||
GA ~func(E) ET.Either[L, A],
|
||||
GB ~func(E) ET.Either[L, B],
|
||||
GC ~func(E) ET.Either[L, C],
|
||||
GTABC ~func(E) ET.Either[L, T.Tuple3[A, B, C]],
|
||||
L, E, A, B, C any](a GA, b GB, c GC) GTABC {
|
||||
return apply.SequenceT3(
|
||||
Map[GA, func(E) ET.Either[L, func(B) func(C) T.Tuple3[A, B, C]], L, E, A, func(B) func(C) T.Tuple3[A, B, C]],
|
||||
Ap[GB, func(E) ET.Either[L, func(C) T.Tuple3[A, B, C]], func(E) ET.Either[L, func(B) func(C) T.Tuple3[A, B, C]], L, E, B, func(C) T.Tuple3[A, B, C]],
|
||||
Ap[GC, GTABC, func(E) ET.Either[L, func(C) T.Tuple3[A, B, C]], L, E, C, T.Tuple3[A, B, C]],
|
||||
|
||||
a, b, c,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceT4[
|
||||
GA ~func(E) ET.Either[L, A],
|
||||
GB ~func(E) ET.Either[L, B],
|
||||
GC ~func(E) ET.Either[L, C],
|
||||
GD ~func(E) ET.Either[L, D],
|
||||
GTABCD ~func(E) ET.Either[L, T.Tuple4[A, B, C, D]],
|
||||
L, E, A, B, C, D any](a GA, b GB, c GC, d GD) GTABCD {
|
||||
return apply.SequenceT4(
|
||||
Map[GA, func(E) ET.Either[L, func(B) func(C) func(D) T.Tuple4[A, B, C, D]], L, E, A, func(B) func(C) func(D) T.Tuple4[A, B, C, D]],
|
||||
Ap[GB, func(E) ET.Either[L, func(C) func(D) T.Tuple4[A, B, C, D]], func(E) ET.Either[L, func(B) func(C) func(D) T.Tuple4[A, B, C, D]], L, E, B, func(C) func(D) T.Tuple4[A, B, C, D]],
|
||||
Ap[GC, func(E) ET.Either[L, func(D) T.Tuple4[A, B, C, D]], func(E) ET.Either[L, func(C) func(D) T.Tuple4[A, B, C, D]], L, E, C, func(D) T.Tuple4[A, B, C, D]],
|
||||
Ap[GD, GTABCD, func(E) ET.Either[L, func(D) T.Tuple4[A, B, C, D]], L, E, D, T.Tuple4[A, B, C, D]],
|
||||
|
||||
a, b, c, d,
|
||||
)
|
||||
}
|
130
readereither/reader.go
Normal file
130
readereither/reader.go
Normal file
@ -0,0 +1,130 @@
|
||||
package readereither
|
||||
|
||||
import (
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
O "github.com/ibm/fp-go/option"
|
||||
R "github.com/ibm/fp-go/reader"
|
||||
G "github.com/ibm/fp-go/readereither/generic"
|
||||
)
|
||||
|
||||
type ReaderEither[E, L, A any] R.Reader[E, ET.Either[L, A]]
|
||||
|
||||
func MakeReaderEither[L, E, A any](f func(E) ET.Either[L, A]) ReaderEither[E, L, A] {
|
||||
return G.MakeReaderEither[ReaderEither[E, L, A]](f)
|
||||
}
|
||||
|
||||
func FromEither[E, L, A any](e ET.Either[L, A]) ReaderEither[E, L, A] {
|
||||
return G.FromEither[ReaderEither[E, L, A]](e)
|
||||
}
|
||||
|
||||
func RightReader[E, L, A any](r R.Reader[E, A]) ReaderEither[E, L, A] {
|
||||
return G.RightReader[R.Reader[E, A], ReaderEither[E, L, A]](r)
|
||||
}
|
||||
|
||||
func LeftReader[E, L, A any](l R.Reader[E, L]) ReaderEither[E, L, A] {
|
||||
return G.LeftReader[R.Reader[E, L], ReaderEither[E, L, A]](l)
|
||||
}
|
||||
|
||||
func Left[E, L, A any](l L) ReaderEither[E, L, A] {
|
||||
return G.Left[ReaderEither[E, L, A]](l)
|
||||
}
|
||||
|
||||
func Right[E, L, A any](r A) ReaderEither[E, L, A] {
|
||||
return G.Right[ReaderEither[E, L, A]](r)
|
||||
}
|
||||
|
||||
func FromReader[E, L, A any](r R.Reader[E, A]) ReaderEither[E, L, A] {
|
||||
return G.FromReader[R.Reader[E, A], ReaderEither[E, L, A]](r)
|
||||
}
|
||||
|
||||
func MonadMap[E, L, A, B any](fa ReaderEither[E, L, A], f func(A) B) ReaderEither[E, L, B] {
|
||||
return G.MonadMap[ReaderEither[E, L, A], ReaderEither[E, L, B]](fa, f)
|
||||
}
|
||||
|
||||
func Map[E, L, A, B any](f func(A) B) func(ReaderEither[E, L, A]) ReaderEither[E, L, B] {
|
||||
return G.Map[ReaderEither[E, L, A], ReaderEither[E, L, B]](f)
|
||||
}
|
||||
|
||||
func MonadChain[E, L, A, B any](ma ReaderEither[E, L, A], f func(A) ReaderEither[E, L, B]) ReaderEither[E, L, B] {
|
||||
return G.MonadChain[ReaderEither[E, L, A], ReaderEither[E, L, B]](ma, f)
|
||||
}
|
||||
|
||||
func Chain[E, L, A, B any](f func(A) ReaderEither[E, L, B]) func(ReaderEither[E, L, A]) ReaderEither[E, L, B] {
|
||||
return G.Chain[ReaderEither[E, L, A], ReaderEither[E, L, B]](f)
|
||||
}
|
||||
|
||||
func Of[E, L, A any](a A) ReaderEither[E, L, A] {
|
||||
return G.Of[ReaderEither[E, L, A]](a)
|
||||
}
|
||||
|
||||
func MonadAp[E, L, A, B any](fab ReaderEither[E, L, func(A) B], fa ReaderEither[E, L, A]) ReaderEither[E, L, B] {
|
||||
return G.MonadAp[ReaderEither[E, L, A], ReaderEither[E, L, B], ReaderEither[E, L, func(A) B]](fab, fa)
|
||||
}
|
||||
|
||||
func Ap[E, L, A, B any](fa ReaderEither[E, L, A]) func(ReaderEither[E, L, func(A) B]) ReaderEither[E, L, B] {
|
||||
return G.Ap[ReaderEither[E, L, A], ReaderEither[E, L, B], ReaderEither[E, L, func(A) B]](fa)
|
||||
}
|
||||
|
||||
func FromPredicate[E, L, A any](pred func(A) bool, onFalse func(A) L) func(A) ReaderEither[E, L, A] {
|
||||
return G.FromPredicate[ReaderEither[E, L, A]](pred, onFalse)
|
||||
}
|
||||
|
||||
func Fold[E, L, A, B any](onLeft func(L) R.Reader[E, B], onRight func(A) R.Reader[E, B]) func(ReaderEither[E, L, A]) R.Reader[E, B] {
|
||||
return G.Fold[ReaderEither[E, L, A]](onLeft, onRight)
|
||||
}
|
||||
|
||||
func GetOrElse[E, L, A any](onLeft func(L) R.Reader[E, A]) func(ReaderEither[E, L, A]) R.Reader[E, A] {
|
||||
return G.GetOrElse[ReaderEither[E, L, A]](onLeft)
|
||||
}
|
||||
|
||||
func OrElse[E, L1, A, L2 any](onLeft func(L1) ReaderEither[E, L2, A]) func(ReaderEither[E, L1, A]) ReaderEither[E, L2, A] {
|
||||
return G.OrElse[ReaderEither[E, L1, A]](onLeft)
|
||||
}
|
||||
|
||||
func OrLeft[L1, E, L2, A any](onLeft func(L1) R.Reader[E, L2]) func(ReaderEither[E, L1, A]) ReaderEither[E, L2, A] {
|
||||
return G.OrLeft[ReaderEither[E, L1, A], ReaderEither[E, L2, A]](onLeft)
|
||||
}
|
||||
|
||||
func Ask[E, L any]() ReaderEither[E, L, E] {
|
||||
return G.Ask[ReaderEither[E, L, E]]()
|
||||
}
|
||||
|
||||
func Asks[E, L, A any](r R.Reader[E, A]) ReaderEither[E, L, A] {
|
||||
return G.Asks[R.Reader[E, A], ReaderEither[E, L, A]](r)
|
||||
}
|
||||
|
||||
func MonadChainEitherK[E, L, A, B any](ma ReaderEither[E, L, A], f func(A) ET.Either[L, B]) ReaderEither[E, L, B] {
|
||||
return G.MonadChainEitherK[ReaderEither[E, L, A], ReaderEither[E, L, B]](ma, f)
|
||||
}
|
||||
|
||||
func ChainEitherK[E, L, A, B any](f func(A) ET.Either[L, B]) func(ma ReaderEither[E, L, A]) ReaderEither[E, L, B] {
|
||||
return G.ChainEitherK[ReaderEither[E, L, A], ReaderEither[E, L, B]](f)
|
||||
}
|
||||
|
||||
func ChainOptionK[E, L, A, B any](onNone func() L) func(func(A) O.Option[B]) func(ReaderEither[E, L, A]) ReaderEither[E, L, B] {
|
||||
return G.ChainOptionK[ReaderEither[E, L, A], ReaderEither[E, L, B]](onNone)
|
||||
}
|
||||
|
||||
func Flatten[E, L, A any](mma ReaderEither[E, L, ReaderEither[E, L, A]]) ReaderEither[E, L, A] {
|
||||
return G.Flatten(mma)
|
||||
}
|
||||
|
||||
func MonadBiMap[E, E1, E2, A, B any](fa ReaderEither[E, E1, A], f func(E1) E2, g func(A) B) ReaderEither[E, E2, B] {
|
||||
return G.MonadBiMap[ReaderEither[E, E1, A], ReaderEither[E, E2, B]](fa, f, g)
|
||||
}
|
||||
|
||||
// BiMap maps a pair of functions over the two type arguments of the bifunctor.
|
||||
func BiMap[E, E1, E2, A, B any](f func(E1) E2, g func(A) B) func(ReaderEither[E, E1, A]) ReaderEither[E, E2, B] {
|
||||
return G.BiMap[ReaderEither[E, E1, A], ReaderEither[E, E2, B]](f, g)
|
||||
}
|
||||
|
||||
// Local changes the value of the local context during the execution of the action `ma` (similar to `Contravariant`'s
|
||||
// `contramap`).
|
||||
func Local[R2, R1, E, A any](f func(R2) R1) func(ReaderEither[R1, E, A]) ReaderEither[R2, E, A] {
|
||||
return G.Local[ReaderEither[R1, E, A], ReaderEither[R2, E, A]](f)
|
||||
}
|
||||
|
||||
// Read applies a context to a reader to obtain its value
|
||||
func Read[E, E1, A any](e E) func(ReaderEither[E, E1, A]) ET.Either[E1, A] {
|
||||
return G.Read[ReaderEither[E, E1, A]](e)
|
||||
}
|
44
readereither/reader_test.go
Normal file
44
readereither/reader_test.go
Normal file
@ -0,0 +1,44 @@
|
||||
package readereither
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
F "github.com/ibm/fp-go/function"
|
||||
"github.com/ibm/fp-go/internal/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type MyContext string
|
||||
|
||||
const defaultContext MyContext = "default"
|
||||
|
||||
func TestMap(t *testing.T) {
|
||||
|
||||
g := F.Pipe1(
|
||||
Of[MyContext, error](1),
|
||||
Map[MyContext, error](utils.Double),
|
||||
)
|
||||
|
||||
assert.Equal(t, ET.Of[error](2), g(defaultContext))
|
||||
|
||||
}
|
||||
|
||||
func TestAp(t *testing.T) {
|
||||
g := F.Pipe1(
|
||||
Of[MyContext, error](utils.Double),
|
||||
Ap[MyContext, error, int, int](Of[MyContext, error](1)),
|
||||
)
|
||||
assert.Equal(t, ET.Of[error](2), g(defaultContext))
|
||||
|
||||
}
|
||||
|
||||
func TestFlatten(t *testing.T) {
|
||||
|
||||
g := F.Pipe1(
|
||||
Of[MyContext, string](Of[MyContext, string]("a")),
|
||||
Flatten[MyContext, string, string],
|
||||
)
|
||||
|
||||
assert.Equal(t, ET.Of[string]("a"), g(defaultContext))
|
||||
}
|
54
readereither/sequence.go
Normal file
54
readereither/sequence.go
Normal file
@ -0,0 +1,54 @@
|
||||
package readereither
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/readereither/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[L, E, A any](a ReaderEither[E, L, A]) ReaderEither[E, L, T.Tuple1[A]] {
|
||||
return G.SequenceT1[
|
||||
ReaderEither[E, L, A],
|
||||
ReaderEither[E, L, T.Tuple1[A]],
|
||||
](a)
|
||||
}
|
||||
|
||||
func SequenceT2[L, E, A, B any](
|
||||
a ReaderEither[E, L, A],
|
||||
b ReaderEither[E, L, B],
|
||||
) ReaderEither[E, L, T.Tuple2[A, B]] {
|
||||
return G.SequenceT2[
|
||||
ReaderEither[E, L, A],
|
||||
ReaderEither[E, L, B],
|
||||
ReaderEither[E, L, T.Tuple2[A, B]],
|
||||
](a, b)
|
||||
}
|
||||
|
||||
func SequenceT3[L, E, A, B, C any](
|
||||
a ReaderEither[E, L, A],
|
||||
b ReaderEither[E, L, B],
|
||||
c ReaderEither[E, L, C],
|
||||
) ReaderEither[E, L, T.Tuple3[A, B, C]] {
|
||||
return G.SequenceT3[
|
||||
ReaderEither[E, L, A],
|
||||
ReaderEither[E, L, B],
|
||||
ReaderEither[E, L, C],
|
||||
ReaderEither[E, L, T.Tuple3[A, B, C]],
|
||||
](a, b, c)
|
||||
}
|
||||
|
||||
func SequenceT4[L, E, A, B, C, D any](
|
||||
a ReaderEither[E, L, A],
|
||||
b ReaderEither[E, L, B],
|
||||
c ReaderEither[E, L, C],
|
||||
d ReaderEither[E, L, D],
|
||||
) ReaderEither[E, L, T.Tuple4[A, B, C, D]] {
|
||||
return G.SequenceT4[
|
||||
ReaderEither[E, L, A],
|
||||
ReaderEither[E, L, B],
|
||||
ReaderEither[E, L, C],
|
||||
ReaderEither[E, L, D],
|
||||
ReaderEither[E, L, T.Tuple4[A, B, C, D]],
|
||||
](a, b, c, d)
|
||||
}
|
77
readereither/sequence_test.go
Normal file
77
readereither/sequence_test.go
Normal file
@ -0,0 +1,77 @@
|
||||
package readereither
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
E "github.com/ibm/fp-go/either"
|
||||
T "github.com/ibm/fp-go/tuple"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
testError = fmt.Errorf("error")
|
||||
)
|
||||
|
||||
func TestSequenceT1(t *testing.T) {
|
||||
|
||||
t1 := Of[MyContext, error]("s1")
|
||||
e1 := Left[MyContext, error, string](testError)
|
||||
|
||||
res1 := SequenceT1(t1)
|
||||
assert.Equal(t, E.Of[error](T.MakeTuple1("s1")), res1(defaultContext))
|
||||
|
||||
res2 := SequenceT1(e1)
|
||||
assert.Equal(t, E.Left[T.Tuple1[string]](testError), res2(defaultContext))
|
||||
}
|
||||
|
||||
func TestSequenceT2(t *testing.T) {
|
||||
|
||||
t1 := Of[MyContext, error]("s1")
|
||||
e1 := Left[MyContext, error, string](testError)
|
||||
t2 := Of[MyContext, error](2)
|
||||
e2 := Left[MyContext, error, int](testError)
|
||||
|
||||
res1 := SequenceT2(t1, t2)
|
||||
assert.Equal(t, E.Of[error](T.MakeTuple2("s1", 2)), res1(defaultContext))
|
||||
|
||||
res2 := SequenceT2(e1, t2)
|
||||
assert.Equal(t, E.Left[T.Tuple2[string, int]](testError), res2(defaultContext))
|
||||
|
||||
res3 := SequenceT2(t1, e2)
|
||||
assert.Equal(t, E.Left[T.Tuple2[string, int]](testError), res3(defaultContext))
|
||||
}
|
||||
|
||||
func TestSequenceT3(t *testing.T) {
|
||||
|
||||
t1 := Of[MyContext, error]("s1")
|
||||
e1 := Left[MyContext, error, string](testError)
|
||||
t2 := Of[MyContext, error](2)
|
||||
e2 := Left[MyContext, error, int](testError)
|
||||
t3 := Of[MyContext, error](true)
|
||||
e3 := Left[MyContext, error, bool](testError)
|
||||
|
||||
res1 := SequenceT3(t1, t2, t3)
|
||||
assert.Equal(t, E.Of[error](T.MakeTuple3("s1", 2, true)), res1(defaultContext))
|
||||
|
||||
res2 := SequenceT3(e1, t2, t3)
|
||||
assert.Equal(t, E.Left[T.Tuple3[string, int, bool]](testError), res2(defaultContext))
|
||||
|
||||
res3 := SequenceT3(t1, e2, t3)
|
||||
assert.Equal(t, E.Left[T.Tuple3[string, int, bool]](testError), res3(defaultContext))
|
||||
|
||||
res4 := SequenceT3(t1, t2, e3)
|
||||
assert.Equal(t, E.Left[T.Tuple3[string, int, bool]](testError), res4(defaultContext))
|
||||
}
|
||||
|
||||
func TestSequenceT4(t *testing.T) {
|
||||
|
||||
t1 := Of[MyContext, error]("s1")
|
||||
t2 := Of[MyContext, error](2)
|
||||
t3 := Of[MyContext, error](true)
|
||||
t4 := Of[MyContext, error](1.0)
|
||||
|
||||
res := SequenceT4(t1, t2, t3, t4)
|
||||
|
||||
assert.Equal(t, E.Of[error](T.MakeTuple4("s1", 2, true, 1.0)), res(defaultContext))
|
||||
}
|
25
readerio/ap.go
Normal file
25
readerio/ap.go
Normal file
@ -0,0 +1,25 @@
|
||||
package readerio
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/readerio/generic"
|
||||
)
|
||||
|
||||
// MonadApFirst combines two effectful actions, keeping only the result of the first.
|
||||
func MonadApFirst[R, A, B any](first ReaderIO[R, A], second ReaderIO[R, B]) ReaderIO[R, A] {
|
||||
return G.MonadApFirst[ReaderIO[R, A], ReaderIO[R, B], ReaderIO[R, func(B) A]](first, second)
|
||||
}
|
||||
|
||||
// ApFirst combines two effectful actions, keeping only the result of the first.
|
||||
func ApFirst[R, A, B any](second ReaderIO[R, B]) func(ReaderIO[R, A]) ReaderIO[R, A] {
|
||||
return G.ApFirst[ReaderIO[R, A], ReaderIO[R, B], ReaderIO[R, func(B) A]](second)
|
||||
}
|
||||
|
||||
// MonadApSecond combines two effectful actions, keeping only the result of the second.
|
||||
func MonadApSecond[R, A, B any](first ReaderIO[R, A], second ReaderIO[R, B]) ReaderIO[R, B] {
|
||||
return G.MonadApSecond[ReaderIO[R, A], ReaderIO[R, B], ReaderIO[R, func(B) B]](first, second)
|
||||
}
|
||||
|
||||
// ApSecond combines two effectful actions, keeping only the result of the second.
|
||||
func ApSecond[R, A, B any](second ReaderIO[R, B]) func(ReaderIO[R, A]) ReaderIO[R, B] {
|
||||
return G.ApSecond[ReaderIO[R, A], ReaderIO[R, B], ReaderIO[R, func(B) B]](second)
|
||||
}
|
16
readerio/array.go
Normal file
16
readerio/array.go
Normal file
@ -0,0 +1,16 @@
|
||||
package readerio
|
||||
|
||||
import (
|
||||
IO "github.com/ibm/fp-go/io"
|
||||
G "github.com/ibm/fp-go/readerio/generic"
|
||||
)
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func TraverseArray[R, A, B any](f func(A) ReaderIO[R, B]) func([]A) ReaderIO[R, []B] {
|
||||
return G.TraverseArray[ReaderIO[R, B], ReaderIO[R, []B], IO.IO[B], IO.IO[[]B], []A](f)
|
||||
}
|
||||
|
||||
// SequenceArray converts a homogeneous sequence of Readers into a Reader of sequence
|
||||
func SequenceArray[R, A any](ma []ReaderIO[R, A]) ReaderIO[R, []A] {
|
||||
return G.SequenceArray[ReaderIO[R, A], ReaderIO[R, []A]](ma)
|
||||
}
|
19
readerio/array_test.go
Normal file
19
readerio/array_test.go
Normal file
@ -0,0 +1,19 @@
|
||||
package readerio
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
A "github.com/ibm/fp-go/array"
|
||||
F "github.com/ibm/fp-go/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTraverseArray(t *testing.T) {
|
||||
f := TraverseArray(func(a string) ReaderIO[context.Context, string] {
|
||||
return Of[context.Context](a + a)
|
||||
})
|
||||
ctx := context.Background()
|
||||
assert.Equal(t, A.Empty[string](), F.Pipe1(A.Empty[string](), f)(ctx)())
|
||||
assert.Equal(t, []string{"aa", "bb"}, F.Pipe1([]string{"a", "b"}, f)(ctx)())
|
||||
}
|
11
readerio/eq.go
Normal file
11
readerio/eq.go
Normal file
@ -0,0 +1,11 @@
|
||||
package readerio
|
||||
|
||||
import (
|
||||
EQ "github.com/ibm/fp-go/eq"
|
||||
G "github.com/ibm/fp-go/readerio/generic"
|
||||
)
|
||||
|
||||
// Eq implements the equals predicate for values contained in the IO monad
|
||||
func Eq[R, A any](e EQ.Eq[A]) func(r R) EQ.Eq[ReaderIO[R, A]] {
|
||||
return G.Eq[ReaderIO[R, A]](e)
|
||||
}
|
25
readerio/from.go
Normal file
25
readerio/from.go
Normal file
@ -0,0 +1,25 @@
|
||||
package readerio
|
||||
|
||||
import (
|
||||
IO "github.com/ibm/fp-go/io"
|
||||
G "github.com/ibm/fp-go/readerio/generic"
|
||||
)
|
||||
|
||||
// these functions From a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func From0[R, A any](f func(R) IO.IO[A]) ReaderIO[R, A] {
|
||||
return G.From0[ReaderIO[R, A]](f)
|
||||
}
|
||||
|
||||
func From1[R, T1, A any](f func(R, T1) IO.IO[A]) func(T1) ReaderIO[R, A] {
|
||||
return G.From1[ReaderIO[R, A]](f)
|
||||
}
|
||||
|
||||
func From2[R, T1, T2, A any](f func(R, T1, T2) IO.IO[A]) func(T1, T2) ReaderIO[R, A] {
|
||||
return G.From2[ReaderIO[R, A]](f)
|
||||
}
|
||||
|
||||
func From3[R, T1, T2, T3, A any](f func(R, T1, T2, T3) IO.IO[A]) func(T1, T2, T3) ReaderIO[R, A] {
|
||||
return G.From3[ReaderIO[R, A]](f)
|
||||
}
|
47
readerio/generic/ap.go
Normal file
47
readerio/generic/ap.go
Normal file
@ -0,0 +1,47 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/internal/apply"
|
||||
)
|
||||
|
||||
// MonadApFirst combines two effectful actions, keeping only the result of the first.
|
||||
func MonadApFirst[GRA ~func(R) GA, GRB ~func(R) GB, GRBA ~func(R) GBA, GA ~func() A, GB ~func() B, GBA ~func() func(B) A, R, A, B any](first GRA, second GRB) GRA {
|
||||
return G.MonadApFirst(
|
||||
MonadAp[GRB, GRA, GRBA, GB, GA, GBA, R, B, A],
|
||||
MonadMap[GRA, GRBA, GA, GBA, R, A, func(B) A],
|
||||
|
||||
first,
|
||||
second,
|
||||
)
|
||||
}
|
||||
|
||||
// ApFirst combines two effectful actions, keeping only the result of the first.
|
||||
func ApFirst[GRA ~func(R) GA, GRB ~func(R) GB, GRBA ~func(R) GBA, GA ~func() A, GB ~func() B, GBA ~func() func(B) A, R, A, B any](second GRB) func(GRA) GRA {
|
||||
return G.ApFirst(
|
||||
MonadAp[GRB, GRA, GRBA, GB, GA, GBA, R, B, A],
|
||||
MonadMap[GRA, GRBA, GA, GBA, R, A, func(B) A],
|
||||
|
||||
second,
|
||||
)
|
||||
}
|
||||
|
||||
// MonadApSecond combines two effectful actions, keeping only the result of the second.
|
||||
func MonadApSecond[GRA ~func(R) GA, GRB ~func(R) GB, GRBB ~func(R) GBB, GA ~func() A, GB ~func() B, GBB ~func() func(B) B, R, A, B any](first GRA, second GRB) GRB {
|
||||
return G.MonadApSecond(
|
||||
MonadAp[GRB, GRB, GRBB, GB, GB, GBB, R, B, B],
|
||||
MonadMap[GRA, GRBB, GA, GBB, R, A, func(B) B],
|
||||
|
||||
first,
|
||||
second,
|
||||
)
|
||||
}
|
||||
|
||||
// ApSecond combines two effectful actions, keeping only the result of the second.
|
||||
func ApSecond[GRA ~func(R) GA, GRB ~func(R) GB, GRBB ~func(R) GBB, GA ~func() A, GB ~func() B, GBB ~func() func(B) B, R, A, B any](second GRB) func(GRA) GRB {
|
||||
return G.ApSecond(
|
||||
MonadAp[GRB, GRB, GRBB, GB, GB, GBB, R, B, B],
|
||||
MonadMap[GRA, GRBB, GA, GBB, R, A, func(B) B],
|
||||
|
||||
second,
|
||||
)
|
||||
}
|
33
readerio/generic/array.go
Normal file
33
readerio/generic/array.go
Normal file
@ -0,0 +1,33 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
F "github.com/ibm/fp-go/function"
|
||||
RA "github.com/ibm/fp-go/internal/array"
|
||||
)
|
||||
|
||||
// MonadTraverseArray transforms an array
|
||||
func MonadTraverseArray[GB ~func(E) GIOB, GBS ~func(E) GIOBS, GIOB ~func() B, GIOBS ~func() BBS, AAS ~[]A, BBS ~[]B, E, A, B any](ma AAS, f func(A) GB) GBS {
|
||||
return RA.MonadTraverse[AAS](
|
||||
Of[GBS, GIOBS, E, BBS],
|
||||
Map[GBS, func(E) func() func(B) BBS, GIOBS, func() func(B) BBS, E, BBS, func(B) BBS],
|
||||
Ap[GB, GBS, func(E) func() func(B) BBS, GIOB, GIOBS, func() func(B) BBS, E, B, BBS],
|
||||
|
||||
ma, f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func TraverseArray[GB ~func(E) GIOB, GBS ~func(E) GIOBS, GIOB ~func() B, GIOBS ~func() BBS, AAS ~[]A, BBS ~[]B, E, A, B any](f func(A) GB) func(AAS) GBS {
|
||||
return RA.Traverse[AAS](
|
||||
Of[GBS, GIOBS, E, BBS],
|
||||
Map[GBS, func(E) func() func(B) BBS, GIOBS, func() func(B) BBS, E, BBS, func(B) BBS],
|
||||
Ap[GB, GBS, func(E) func() func(B) BBS, GIOB, GIOBS, func() func(B) BBS, E, B, BBS],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArray[GA ~func(E) GIOA, GAS ~func(E) GIOAS, GIOA ~func() A, GIOAS ~func() AAS, AAS ~[]A, GAAS ~[]GA, E, A any](ma GAAS) GAS {
|
||||
return MonadTraverseArray[GA, GAS](ma, F.Identity[GA])
|
||||
}
|
22
readerio/generic/eq.go
Normal file
22
readerio/generic/eq.go
Normal file
@ -0,0 +1,22 @@
|
||||
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[GEA ~func(R) GIOA, GIOA ~func() A, R, A any](e EQ.Eq[A]) func(r R) EQ.Eq[GEA] {
|
||||
// comparator for the monad
|
||||
eq := G.Eq(
|
||||
MonadMap[GEA, func(R) func() func(A) bool, GIOA, func() func(A) bool, R, A, func(A) bool],
|
||||
MonadAp[GEA, func(R) func() bool, func(R) func() func(A) bool],
|
||||
e,
|
||||
)
|
||||
// eagerly execute
|
||||
return func(ctx R) EQ.Eq[GEA] {
|
||||
return EQ.FromEquals(func(l, r GEA) bool {
|
||||
return eq(l, r)(ctx)()
|
||||
})
|
||||
}
|
||||
}
|
24
readerio/generic/from.go
Normal file
24
readerio/generic/from.go
Normal file
@ -0,0 +1,24 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
// these functions From a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func From0[GEA ~func(R) GIOA, GIOA ~func() A, R, A any](f func(R) GIOA) GEA {
|
||||
return G.From0[GEA](f)
|
||||
}
|
||||
|
||||
func From1[GEA ~func(R) GIOA, GIOA ~func() A, R, T1, A any](f func(R, T1) GIOA) func(T1) GEA {
|
||||
return G.From1[GEA](f)
|
||||
}
|
||||
|
||||
func From2[GEA ~func(R) GIOA, GIOA ~func() A, R, T1, T2, A any](f func(R, T1, T2) GIOA) func(T1, T2) GEA {
|
||||
return G.From2[GEA](f)
|
||||
}
|
||||
|
||||
func From3[GEA ~func(R) GIOA, GIOA ~func() A, R, T1, T2, T3, A any](f func(R, T1, T2, T3) GIOA) func(T1, T2, T3) GEA {
|
||||
return G.From3[GEA](f)
|
||||
}
|
70
readerio/generic/reader.go
Normal file
70
readerio/generic/reader.go
Normal file
@ -0,0 +1,70 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
F "github.com/ibm/fp-go/function"
|
||||
FR "github.com/ibm/fp-go/internal/fromreader"
|
||||
"github.com/ibm/fp-go/internal/readert"
|
||||
IO "github.com/ibm/fp-go/io/generic"
|
||||
R "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
func FromIO[GEA ~func(E) GIOA, GIOA ~func() A, E, A any](t GIOA) GEA {
|
||||
return R.Of[GEA, E](t)
|
||||
}
|
||||
|
||||
func FromReader[GA ~func(E) A, GEA ~func(E) GIOA, GIOA ~func() A, E, A any](r GA) GEA {
|
||||
return readert.MonadFromReader[GA, GEA](IO.Of[GIOA, A], r)
|
||||
}
|
||||
|
||||
func MonadMap[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func() B, E, A, B any](fa GEA, f func(A) B) GEB {
|
||||
return readert.MonadMap[GEA, GEB](IO.MonadMap[GIOA, GIOB, A, B], fa, f)
|
||||
}
|
||||
|
||||
func Map[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func() B, E, A, B any](f func(A) B) func(GEA) GEB {
|
||||
return F.Bind2nd(MonadMap[GEA, GEB, GIOA, GIOB, E, A, B], f)
|
||||
}
|
||||
|
||||
func MonadChain[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func() B, E, A, B any](ma GEA, f func(A) GEB) GEB {
|
||||
return readert.MonadChain(IO.MonadChain[GIOA, GIOB, A, B], ma, f)
|
||||
}
|
||||
|
||||
func Chain[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func() B, E, A, B any](f func(A) GEB) func(GEA) GEB {
|
||||
return F.Bind2nd(MonadChain[GEA, GEB, GIOA, GIOB, E, A, B], f)
|
||||
}
|
||||
|
||||
func Of[GEA ~func(E) GIOA, GIOA ~func() A, E, A any](a A) GEA {
|
||||
return readert.MonadOf[GEA](IO.Of[GIOA, A], a)
|
||||
}
|
||||
|
||||
func MonadAp[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GEFAB ~func(E) GIOFAB, GIOA ~func() A, GIOB ~func() B, GIOFAB ~func() func(A) B, E, A, B any](fab GEFAB, fa GEA) GEB {
|
||||
return readert.MonadAp[GEA, GEB, GEFAB, E, A](IO.MonadAp[GIOA, GIOB, GIOFAB, A, B], fab, fa)
|
||||
}
|
||||
|
||||
func Ap[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GEFAB ~func(E) GIOFAB, GIOA ~func() A, GIOB ~func() B, GIOFAB ~func() func(A) B, E, A, B any](fa GEA) func(GEFAB) GEB {
|
||||
return F.Bind2nd(MonadAp[GEA, GEB, GEFAB, GIOA, GIOB, GIOFAB, E, A, B], fa)
|
||||
}
|
||||
|
||||
func Ask[GEE ~func(E) GIOE, GIOE ~func() E, E any]() GEE {
|
||||
return FR.Ask(FromReader[func(E) E, GEE, GIOE, E, E])()
|
||||
}
|
||||
|
||||
func Asks[GA ~func(E) A, GEA ~func(E) GIOA, GIOA ~func() A, E, A any](r GA) GEA {
|
||||
return FR.Asks(FromReader[GA, GEA, GIOA, E, A])(r)
|
||||
}
|
||||
|
||||
func MonadChainIOK[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func() B, E, A, B any](ma GEA, f func(A) GIOB) GEB {
|
||||
return MonadChain(ma, F.Flow2(f, FromIO[GEB]))
|
||||
}
|
||||
|
||||
func ChainIOK[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func() B, E, A, B any](f func(A) GIOB) func(GEA) GEB {
|
||||
return F.Bind2nd(MonadChainIOK[GEA, GEB, GIOA, GIOB, E, A, B], f)
|
||||
}
|
||||
|
||||
// Defer creates an IO by creating a brand new IO via a generator function, each time
|
||||
func Defer[GEA ~func(E) GA, GA ~func() A, E, A any](gen func() GEA) GEA {
|
||||
return func(e E) GA {
|
||||
return func() A {
|
||||
return gen()(e)()
|
||||
}
|
||||
}
|
||||
}
|
78
readerio/generic/sequence.go
Normal file
78
readerio/generic/sequence.go
Normal file
@ -0,0 +1,78 @@
|
||||
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(E) GIOA,
|
||||
GTA ~func(E) GIOTA,
|
||||
GIOA ~func() A,
|
||||
GIOTA ~func() T.Tuple1[A],
|
||||
E, A any](a GA) GTA {
|
||||
return apply.SequenceT1(
|
||||
Map[GA, GTA, GIOA, GIOTA, E, A, T.Tuple1[A]],
|
||||
|
||||
a,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceT2[
|
||||
GA ~func(E) GIOA,
|
||||
GB ~func(E) GIOB,
|
||||
GTAB ~func(E) GIOTAB,
|
||||
GIOA ~func() A,
|
||||
GIOB ~func() B,
|
||||
GIOTAB ~func() T.Tuple2[A, B],
|
||||
E, A, B any](a GA, b GB) GTAB {
|
||||
return apply.SequenceT2(
|
||||
Map[GA, func(E) func() func(B) T.Tuple2[A, B], GIOA, func() func(B) T.Tuple2[A, B], E, A, func(B) T.Tuple2[A, B]],
|
||||
Ap[GB, GTAB, func(E) func() func(B) T.Tuple2[A, B], GIOB, GIOTAB, func() func(B) T.Tuple2[A, B], E, B, T.Tuple2[A, B]],
|
||||
|
||||
a, b,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceT3[
|
||||
GA ~func(E) GIOA,
|
||||
GB ~func(E) GIOB,
|
||||
GC ~func(E) GIOC,
|
||||
GTABC ~func(E) GIOTABC,
|
||||
GIOA ~func() A,
|
||||
GIOB ~func() B,
|
||||
GIOC ~func() C,
|
||||
GIOTABC ~func() T.Tuple3[A, B, C],
|
||||
E, A, B, C any](a GA, b GB, c GC) GTABC {
|
||||
return apply.SequenceT3(
|
||||
Map[GA, func(E) func() func(B) func(C) T.Tuple3[A, B, C], GIOA, func() func(B) func(C) T.Tuple3[A, B, C], E, A, func(B) func(C) T.Tuple3[A, B, C]],
|
||||
Ap[GB, func(E) func() func(C) T.Tuple3[A, B, C], func(E) func() func(B) func(C) T.Tuple3[A, B, C], GIOB, func() func(C) T.Tuple3[A, B, C], func() func(B) func(C) T.Tuple3[A, B, C], E, B, func(C) T.Tuple3[A, B, C]],
|
||||
Ap[GC, GTABC, func(E) func() func(C) T.Tuple3[A, B, C], GIOC, GIOTABC, func() func(C) T.Tuple3[A, B, C], E, C, T.Tuple3[A, B, C]],
|
||||
|
||||
a, b, c,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceT4[
|
||||
GA ~func(E) GIOA,
|
||||
GB ~func(E) GIOB,
|
||||
GC ~func(E) GIOC,
|
||||
GD ~func(E) GIOD,
|
||||
GTABCD ~func(E) GIOTABCD,
|
||||
GIOA ~func() A,
|
||||
GIOB ~func() B,
|
||||
GIOC ~func() C,
|
||||
GIOD ~func() D,
|
||||
GIOTABCD ~func() 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(E) func() func(B) func(C) func(D) T.Tuple4[A, B, C, D], GIOA, func() 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(E) func() func(C) func(D) T.Tuple4[A, B, C, D], func(E) func() func(B) func(C) func(D) T.Tuple4[A, B, C, D], GIOB, func() func(C) func(D) T.Tuple4[A, B, C, D], func() 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(E) func() func(D) T.Tuple4[A, B, C, D], func(E) func() func(C) func(D) T.Tuple4[A, B, C, D], GIOC, func() func(D) T.Tuple4[A, B, C, D], func() func(C) func(D) T.Tuple4[A, B, C, D], E, C, func(D) T.Tuple4[A, B, C, D]],
|
||||
Ap[GD, GTABCD, func(E) func() func(D) T.Tuple4[A, B, C, D], GIOD, GIOTABCD, func() func(D) T.Tuple4[A, B, C, D], E, D, T.Tuple4[A, B, C, D]],
|
||||
|
||||
a, b, c, d,
|
||||
)
|
||||
}
|
62
readerio/reader.go
Normal file
62
readerio/reader.go
Normal file
@ -0,0 +1,62 @@
|
||||
package readerio
|
||||
|
||||
import (
|
||||
IO "github.com/ibm/fp-go/io"
|
||||
R "github.com/ibm/fp-go/reader"
|
||||
G "github.com/ibm/fp-go/readerio/generic"
|
||||
)
|
||||
|
||||
type ReaderIO[E, A any] R.Reader[E, IO.IO[A]]
|
||||
|
||||
func FromIO[E, A any](t IO.IO[A]) ReaderIO[E, A] {
|
||||
return G.FromIO[ReaderIO[E, A]](t)
|
||||
}
|
||||
|
||||
func MonadMap[E, A, B any](fa ReaderIO[E, A], f func(A) B) ReaderIO[E, B] {
|
||||
return G.MonadMap[ReaderIO[E, A], ReaderIO[E, B]](fa, f)
|
||||
}
|
||||
|
||||
func Map[E, A, B any](f func(A) B) func(ReaderIO[E, A]) ReaderIO[E, B] {
|
||||
return G.Map[ReaderIO[E, A], ReaderIO[E, B]](f)
|
||||
}
|
||||
|
||||
func MonadChain[E, A, B any](ma ReaderIO[E, A], f func(A) ReaderIO[E, B]) ReaderIO[E, B] {
|
||||
return G.MonadChain(ma, f)
|
||||
}
|
||||
|
||||
func Chain[E, A, B any](f func(A) ReaderIO[E, B]) func(ReaderIO[E, A]) ReaderIO[E, B] {
|
||||
return G.Chain[ReaderIO[E, A]](f)
|
||||
}
|
||||
|
||||
func Of[E, A any](a A) ReaderIO[E, A] {
|
||||
return G.Of[ReaderIO[E, A]](a)
|
||||
}
|
||||
|
||||
func MonadAp[B, E, A any](fab ReaderIO[E, func(A) B], fa ReaderIO[E, A]) ReaderIO[E, B] {
|
||||
return G.MonadAp[ReaderIO[E, A], ReaderIO[E, B]](fab, fa)
|
||||
}
|
||||
|
||||
func Ap[B, E, A any](fa ReaderIO[E, A]) func(ReaderIO[E, func(A) B]) ReaderIO[E, B] {
|
||||
return G.Ap[ReaderIO[E, A], ReaderIO[E, B], ReaderIO[E, func(A) B]](fa)
|
||||
}
|
||||
|
||||
func Ask[E any]() ReaderIO[E, E] {
|
||||
return G.Ask[ReaderIO[E, E]]()
|
||||
}
|
||||
|
||||
func Asks[E, A any](r R.Reader[E, A]) ReaderIO[E, A] {
|
||||
return G.Asks[R.Reader[E, A], ReaderIO[E, A]](r)
|
||||
}
|
||||
|
||||
func MonadChainIOK[E, A, B any](ma ReaderIO[E, A], f func(A) IO.IO[B]) ReaderIO[E, B] {
|
||||
return G.MonadChainIOK[ReaderIO[E, A], ReaderIO[E, B]](ma, f)
|
||||
}
|
||||
|
||||
func ChainIOK[E, A, B any](f func(A) IO.IO[B]) func(ReaderIO[E, A]) ReaderIO[E, B] {
|
||||
return G.ChainIOK[ReaderIO[E, A], ReaderIO[E, B]](f)
|
||||
}
|
||||
|
||||
// Defer creates an IO by creating a brand new IO via a generator function, each time
|
||||
func Defer[E, A any](gen func() ReaderIO[E, A]) ReaderIO[E, A] {
|
||||
return G.Defer[ReaderIO[E, A]](gen)
|
||||
}
|
29
readerio/reader_test.go
Normal file
29
readerio/reader_test.go
Normal file
@ -0,0 +1,29 @@
|
||||
package readerio
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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) {
|
||||
|
||||
g := F.Pipe1(
|
||||
Of[context.Context](1),
|
||||
Map[context.Context](utils.Double),
|
||||
)
|
||||
|
||||
assert.Equal(t, 2, g(context.Background())())
|
||||
}
|
||||
|
||||
func TestAp(t *testing.T) {
|
||||
g := F.Pipe1(
|
||||
Of[context.Context](utils.Double),
|
||||
Ap[int](Of[context.Context](1)),
|
||||
)
|
||||
|
||||
assert.Equal(t, 2, g(context.Background())())
|
||||
}
|
42
readerio/sequence.go
Normal file
42
readerio/sequence.go
Normal file
@ -0,0 +1,42 @@
|
||||
package readerio
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/readerio/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[R, A any](a ReaderIO[R, A]) ReaderIO[R, T.Tuple1[A]] {
|
||||
return G.SequenceT1[
|
||||
ReaderIO[R, A],
|
||||
ReaderIO[R, T.Tuple1[A]],
|
||||
](a)
|
||||
}
|
||||
|
||||
func SequenceT2[R, A, B any](a ReaderIO[R, A], b ReaderIO[R, B]) ReaderIO[R, T.Tuple2[A, B]] {
|
||||
return G.SequenceT2[
|
||||
ReaderIO[R, A],
|
||||
ReaderIO[R, B],
|
||||
ReaderIO[R, T.Tuple2[A, B]],
|
||||
](a, b)
|
||||
}
|
||||
|
||||
func SequenceT3[R, A, B, C any](a ReaderIO[R, A], b ReaderIO[R, B], c ReaderIO[R, C]) ReaderIO[R, T.Tuple3[A, B, C]] {
|
||||
return G.SequenceT3[
|
||||
ReaderIO[R, A],
|
||||
ReaderIO[R, B],
|
||||
ReaderIO[R, C],
|
||||
ReaderIO[R, T.Tuple3[A, B, C]],
|
||||
](a, b, c)
|
||||
}
|
||||
|
||||
func SequenceT4[R, A, B, C, D any](a ReaderIO[R, A], b ReaderIO[R, B], c ReaderIO[R, C], d ReaderIO[R, D]) ReaderIO[R, T.Tuple4[A, B, C, D]] {
|
||||
return G.SequenceT4[
|
||||
ReaderIO[R, A],
|
||||
ReaderIO[R, B],
|
||||
ReaderIO[R, C],
|
||||
ReaderIO[R, D],
|
||||
ReaderIO[R, T.Tuple4[A, B, C, D]],
|
||||
](a, b, c, d)
|
||||
}
|
24
readerioeither/array_test.go
Normal file
24
readerioeither/array_test.go
Normal file
@ -0,0 +1,24 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
A "github.com/ibm/fp-go/array"
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
F "github.com/ibm/fp-go/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTraverseArray(t *testing.T) {
|
||||
f := TraverseArray(func(a string) ReaderIOEither[context.Context, string, string] {
|
||||
if len(a) > 0 {
|
||||
return Right[context.Context, string](a + a)
|
||||
}
|
||||
return Left[context.Context, string, string]("e")
|
||||
})
|
||||
ctx := context.Background()
|
||||
assert.Equal(t, ET.Right[string](A.Empty[string]()), F.Pipe1(A.Empty[string](), f)(ctx)())
|
||||
assert.Equal(t, ET.Right[string]([]string{"aa", "bb"}), F.Pipe1([]string{"a", "b"}, f)(ctx)())
|
||||
assert.Equal(t, ET.Left[[]string]("e"), F.Pipe1([]string{"a", ""}, f)(ctx)())
|
||||
}
|
18
readerioeither/bracket.go
Normal file
18
readerioeither/bracket.go
Normal file
@ -0,0 +1,18 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
G "github.com/ibm/fp-go/readerioeither/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[
|
||||
R, E, A, B, ANY any](
|
||||
|
||||
acquire ReaderIOEither[R, E, A],
|
||||
use func(A) ReaderIOEither[R, E, B],
|
||||
release func(A, ET.Either[E, B]) ReaderIOEither[R, E, ANY],
|
||||
) ReaderIOEither[R, E, B] {
|
||||
return G.Bracket(acquire, use, release)
|
||||
}
|
17
readerioeither/eq.go
Normal file
17
readerioeither/eq.go
Normal file
@ -0,0 +1,17 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
EQ "github.com/ibm/fp-go/eq"
|
||||
G "github.com/ibm/fp-go/readerioeither/generic"
|
||||
)
|
||||
|
||||
// Eq implements the equals predicate for values contained in the IOEither monad
|
||||
func Eq[R, E, A any](eq EQ.Eq[ET.Either[E, A]]) func(R) EQ.Eq[ReaderIOEither[R, E, A]] {
|
||||
return G.Eq[ReaderIOEither[R, E, A]](eq)
|
||||
}
|
||||
|
||||
// FromStrictEquals constructs an `Eq` from the canonical comparison function
|
||||
func FromStrictEquals[R, E, A comparable]() func(R) EQ.Eq[ReaderIOEither[R, E, A]] {
|
||||
return G.FromStrictEquals[ReaderIOEither[R, E, A]]()
|
||||
}
|
24
readerioeither/from.go
Normal file
24
readerioeither/from.go
Normal file
@ -0,0 +1,24 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/readerioeither/generic"
|
||||
)
|
||||
|
||||
// these functions From a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func From0[R, A any](f func(R) func() (A, error)) ReaderIOEither[R, error, A] {
|
||||
return G.From0[ReaderIOEither[R, error, A]](f)
|
||||
}
|
||||
|
||||
func From1[R, T1, A any](f func(R, T1) func() (A, error)) func(T1) ReaderIOEither[R, error, A] {
|
||||
return G.From1[ReaderIOEither[R, error, A]](f)
|
||||
}
|
||||
|
||||
func From2[R, T1, T2, A any](f func(R, T1, T2) func() (A, error)) func(T1, T2) ReaderIOEither[R, error, A] {
|
||||
return G.From2[ReaderIOEither[R, error, A]](f)
|
||||
}
|
||||
|
||||
func From3[R, T1, T2, T3, A any](f func(R, T1, T2, T3) func() (A, error)) func(T1, T2, T3) ReaderIOEither[R, error, A] {
|
||||
return G.From3[ReaderIOEither[R, error, A]](f)
|
||||
}
|
36
readerioeither/generic/bracket.go
Normal file
36
readerioeither/generic/bracket.go
Normal file
@ -0,0 +1,36 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
G "github.com/ibm/fp-go/internal/file"
|
||||
I "github.com/ibm/fp-go/readerio/generic"
|
||||
)
|
||||
|
||||
// Bracket makes sure that a resource is cleaned up in the event of an error. The release action is called regardless of
|
||||
// whether the body action returns and error or not.
|
||||
func Bracket[
|
||||
GA ~func(R) TA,
|
||||
GB ~func(R) TB,
|
||||
GANY ~func(R) TANY,
|
||||
|
||||
TA ~func() ET.Either[E, A],
|
||||
TB ~func() ET.Either[E, B],
|
||||
TANY ~func() ET.Either[E, ANY],
|
||||
|
||||
R, 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, TB, R, ET.Either[E, B]],
|
||||
MonadChain[GA, GB, TA, TB, R, E, A, B],
|
||||
I.MonadChain[GB, GB, TB, TB, R, ET.Either[E, B], ET.Either[E, B]],
|
||||
MonadChain[GANY, GB, TANY, TB, R, E, ANY, B],
|
||||
|
||||
acquire,
|
||||
use,
|
||||
release,
|
||||
)
|
||||
}
|
48
readerioeither/generic/eitherize.go
Normal file
48
readerioeither/generic/eitherize.go
Normal file
@ -0,0 +1,48 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
)
|
||||
|
||||
// these functions From a golang function with the context as the first parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func Eitherize0[GEA ~func(R) GIOA, GIOA ~func() ET.Either[error, A], R, A any](f func(R) (A, error)) GEA {
|
||||
return From0[GEA](func(r R) func() (A, error) {
|
||||
return func() (A, error) {
|
||||
return f(r)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Eitherize1[GEA ~func(R) GIOA, GIOA ~func() ET.Either[error, A], R, T1, A any](f func(R, T1) (A, error)) func(T1) GEA {
|
||||
return From1[GEA](func(r R, t1 T1) func() (A, error) {
|
||||
return func() (A, error) {
|
||||
return f(r, t1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Eitherize2[GEA ~func(R) GIOA, GIOA ~func() ET.Either[error, A], R, T1, T2, A any](f func(R, T1, T2) (A, error)) func(T1, T2) GEA {
|
||||
return From2[GEA](func(r R, t1 T1, t2 T2) func() (A, error) {
|
||||
return func() (A, error) {
|
||||
return f(r, t1, t2)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Eitherize3[GEA ~func(R) GIOA, GIOA ~func() ET.Either[error, A], R, T1, T2, T3, A any](f func(R, T1, T2, T3) (A, error)) func(T1, T2, T3) GEA {
|
||||
return From3[GEA](func(r R, t1 T1, t2 T2, t3 T3) func() (A, error) {
|
||||
return func() (A, error) {
|
||||
return f(r, t1, t2, t3)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Eitherize4[GEA ~func(R) GIOA, GIOA ~func() ET.Either[error, A], R, T1, T2, T3, T4, A any](f func(R, T1, T2, T3, T4) (A, error)) func(T1, T2, T3, T4) GEA {
|
||||
return From4[GEA](func(r R, t1 T1, t2 T2, t3 T3, t4 T4) func() (A, error) {
|
||||
return func() (A, error) {
|
||||
return f(r, t1, t2, t3, t4)
|
||||
}
|
||||
})
|
||||
}
|
17
readerioeither/generic/eq.go
Normal file
17
readerioeither/generic/eq.go
Normal 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/readerio/generic"
|
||||
)
|
||||
|
||||
// Eq implements the equals predicate for values contained in the IOEither monad
|
||||
func Eq[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R, E, A any](eq EQ.Eq[ET.Either[E, A]]) func(R) EQ.Eq[GEA] {
|
||||
return G.Eq[GEA](eq)
|
||||
}
|
||||
|
||||
// FromStrictEquals constructs an `Eq` from the canonical comparison function
|
||||
func FromStrictEquals[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R any, E, A comparable]() func(R) EQ.Eq[GEA] {
|
||||
return Eq[GEA](ET.FromStrictEquals[E, A]())
|
||||
}
|
39
readerioeither/generic/from.go
Normal file
39
readerioeither/generic/from.go
Normal file
@ -0,0 +1,39 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
G "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
// these functions From a golang function with the context as the first parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func From0[GEA ~func(R) GIOA, GIOA ~func() ET.Either[error, A], R, A any](f func(R) func() (A, error)) GEA {
|
||||
return G.From0[GEA](func(r R) GIOA {
|
||||
return ET.Eitherize0(f(r))
|
||||
})
|
||||
}
|
||||
|
||||
func From1[GEA ~func(R) GIOA, GIOA ~func() ET.Either[error, A], R, T1, A any](f func(R, T1) func() (A, error)) func(T1) GEA {
|
||||
return G.From1[GEA](func(r R, t1 T1) GIOA {
|
||||
return ET.Eitherize0(f(r, t1))
|
||||
})
|
||||
}
|
||||
|
||||
func From2[GEA ~func(R) GIOA, GIOA ~func() ET.Either[error, A], R, T1, T2, A any](f func(R, T1, T2) func() (A, error)) func(T1, T2) GEA {
|
||||
return G.From2[GEA](func(r R, t1 T1, t2 T2) GIOA {
|
||||
return ET.Eitherize0(f(r, t1, t2))
|
||||
})
|
||||
}
|
||||
|
||||
func From3[GEA ~func(R) GIOA, GIOA ~func() ET.Either[error, A], R, T1, T2, T3, A any](f func(R, T1, T2, T3) func() (A, error)) func(T1, T2, T3) GEA {
|
||||
return G.From3[GEA](func(r R, t1 T1, t2 T2, t3 T3) GIOA {
|
||||
return ET.Eitherize0(f(r, t1, t2, t3))
|
||||
})
|
||||
}
|
||||
|
||||
func From4[GEA ~func(R) GIOA, GIOA ~func() ET.Either[error, A], R, T1, T2, T3, T4, A any](f func(R, T1, T2, T3, T4) func() (A, error)) func(T1, T2, T3, T4) GEA {
|
||||
return G.From4[GEA](func(r R, t1 T1, t2 T2, t3 T3, t4 T4) GIOA {
|
||||
return ET.Eitherize0(f(r, t1, t2, t3, t4))
|
||||
})
|
||||
}
|
283
readerioeither/generic/reader.go
Normal file
283
readerioeither/generic/reader.go
Normal file
@ -0,0 +1,283 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
F "github.com/ibm/fp-go/function"
|
||||
"github.com/ibm/fp-go/internal/eithert"
|
||||
FE "github.com/ibm/fp-go/internal/fromeither"
|
||||
FIO "github.com/ibm/fp-go/internal/fromio"
|
||||
FIOE "github.com/ibm/fp-go/internal/fromioeither"
|
||||
FR "github.com/ibm/fp-go/internal/fromreader"
|
||||
GIO "github.com/ibm/fp-go/ioeither/generic"
|
||||
IOE "github.com/ibm/fp-go/ioeither/generic"
|
||||
O "github.com/ibm/fp-go/option"
|
||||
RD "github.com/ibm/fp-go/reader/generic"
|
||||
G "github.com/ibm/fp-go/readerio/generic"
|
||||
)
|
||||
|
||||
// MakeReader constructs an instance of a reader
|
||||
func MakeReader[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R, E, A any](f func(R) GIOA) GEA {
|
||||
return f
|
||||
}
|
||||
|
||||
func MonadMap[GEA ~func(R) GIOA, GEB ~func(R) GIOB, GIOA ~func() ET.Either[E, A], GIOB ~func() ET.Either[E, B], R, E, A, B any](fa GEA, f func(A) B) GEB {
|
||||
return eithert.MonadMap(G.MonadMap[GEA, GEB, GIOA, GIOB, R, ET.Either[E, A], ET.Either[E, B]], fa, f)
|
||||
}
|
||||
|
||||
func Map[GEA ~func(R) GIOA, GEB ~func(R) GIOB, GIOA ~func() ET.Either[E, A], GIOB ~func() ET.Either[E, B], R, E, A, B any](f func(A) B) func(GEA) GEB {
|
||||
return F.Bind2nd(MonadMap[GEA, GEB, GIOA, GIOB, R, E, A, B], f)
|
||||
}
|
||||
|
||||
func MonadMapTo[GEA ~func(R) GIOA, GEB ~func(R) GIOB, GIOA ~func() ET.Either[E, A], GIOB ~func() ET.Either[E, B], R, E, A, B any](fa GEA, b B) GEB {
|
||||
return MonadMap[GEA, GEB](fa, F.Constant1[A](b))
|
||||
}
|
||||
|
||||
func MapTo[GEA ~func(R) GIOA, GEB ~func(R) GIOB, GIOA ~func() ET.Either[E, A], GIOB ~func() ET.Either[E, B], R, E, A, B any](b B) func(GEA) GEB {
|
||||
return Map[GEA, GEB](F.Constant1[A](b))
|
||||
}
|
||||
|
||||
func MonadChain[GEA ~func(R) GIOA, GEB ~func(R) GIOB, GIOA ~func() ET.Either[E, A], GIOB ~func() ET.Either[E, B], R, E, A, B any](fa GEA, f func(A) GEB) GEB {
|
||||
return eithert.MonadChain(
|
||||
G.MonadChain[GEA, GEB, GIOA, GIOB, R, ET.Either[E, A], ET.Either[E, B]],
|
||||
G.Of[GEB, GIOB, R, ET.Either[E, B]],
|
||||
fa,
|
||||
f)
|
||||
}
|
||||
|
||||
func Chain[GEA ~func(R) GIOA, GEB ~func(R) GIOB, GIOA ~func() ET.Either[E, A], GIOB ~func() ET.Either[E, B], R, E, A, B any](f func(A) GEB) func(fa GEA) GEB {
|
||||
return F.Bind2nd(MonadChain[GEA, GEB, GIOA, GIOB, R, E, A, B], f)
|
||||
}
|
||||
|
||||
func MonadChainEitherK[GEA ~func(R) GIOA, GEB ~func(R) GIOB, GIOA ~func() ET.Either[E, A], GIOB ~func() ET.Either[E, B], R, E, A, B any](ma GEA, f func(A) ET.Either[E, B]) GEB {
|
||||
return FE.MonadChainEitherK(
|
||||
MonadChain[GEA, GEB, GIOA, GIOB, R, E, A, B],
|
||||
FromEither[GEB, GIOB, R, E, B],
|
||||
ma,
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func ChainEitherK[GEA ~func(R) GIOA, GEB ~func(R) GIOB, GIOA ~func() ET.Either[E, A], GIOB ~func() ET.Either[E, B], R, E, A, B any](f func(A) ET.Either[E, B]) func(ma GEA) GEB {
|
||||
return F.Bind2nd(MonadChainEitherK[GEA, GEB, GIOA, GIOB, R, E, A, B], f)
|
||||
}
|
||||
|
||||
func MonadChainReaderK[GEA ~func(R) GIOA, GEB ~func(R) GIOB, GIOA ~func() ET.Either[E, A], GIOB ~func() ET.Either[E, B], GB ~func(R) B, R, E, A, B any](ma GEA, f func(A) GB) GEB {
|
||||
return FR.MonadChainReaderK(
|
||||
MonadChain[GEA, GEB, GIOA, GIOB, R, E, A, B],
|
||||
FromReader[GB, GEB, GIOB, R, E, B],
|
||||
ma,
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func ChainReaderK[GEA ~func(R) GIOA, GEB ~func(R) GIOB, GIOA ~func() ET.Either[E, A], GIOB ~func() ET.Either[E, B], GB ~func(R) B, R, E, A, B any](f func(A) GB) func(GEA) GEB {
|
||||
return FR.ChainReaderK(
|
||||
MonadChain[GEA, GEB, GIOA, GIOB, R, E, A, B],
|
||||
FromReader[GB, GEB, GIOB, R, E, B],
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func MonadChainIOEitherK[GEA ~func(R) GIOA, GEB ~func(R) GIOB, GIOA ~func() ET.Either[E, A], GIOB ~func() ET.Either[E, B], R, E, A, B any](ma GEA, f func(A) GIOB) GEB {
|
||||
return FIOE.MonadChainIOEitherK(
|
||||
MonadChain[GEA, GEB, GIOA, GIOB, R, E, A, B],
|
||||
FromIOEither[GEB, GIOB, R, E, B],
|
||||
ma,
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func ChainIOEitherK[GEA ~func(R) GIOA, GEB ~func(R) GIOB, GIOA ~func() ET.Either[E, A], GIOB ~func() ET.Either[E, B], R, E, A, B any](f func(A) GIOB) func(GEA) GEB {
|
||||
return F.Bind2nd(MonadChainIOEitherK[GEA, GEB, GIOA, GIOB, R, E, A, B], f)
|
||||
}
|
||||
|
||||
func MonadChainIOK[GEA ~func(R) GIOA, GEB ~func(R) GIOB, GIOA ~func() ET.Either[E, A], GIOB ~func() ET.Either[E, B], GIO ~func() B, R, E, A, B any](ma GEA, f func(A) GIO) GEB {
|
||||
return FIO.MonadChainIOK(
|
||||
MonadChain[GEA, GEB, GIOA, GIOB, R, E, A, B],
|
||||
FromIO[GEB, GIOB, GIO, R, E, B],
|
||||
ma,
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func ChainIOK[GEA ~func(R) GIOA, GEB ~func(R) GIOB, GIOA ~func() ET.Either[E, A], GIOB ~func() ET.Either[E, B], GIO ~func() B, R, E, A, B any](f func(A) GIO) func(GEA) GEB {
|
||||
return F.Bind2nd(MonadChainIOK[GEA, GEB, GIOA, GIOB, GIO, R, E, A, B], f)
|
||||
}
|
||||
|
||||
func ChainOptionK[GEA ~func(R) GIOA, GEB ~func(R) GIOB, GIOA ~func() ET.Either[E, A], GIOB ~func() ET.Either[E, B], R, E, A, B any](onNone func() E) func(func(A) O.Option[B]) func(GEA) GEB {
|
||||
return FE.ChainOptionK(MonadChain[GEA, GEB, GIOA, GIOB, R, E, A, B], FromEither[GEB, GIOB, R, E, B], onNone)
|
||||
}
|
||||
|
||||
func MonadAp[
|
||||
GEA ~func(R) GIOA,
|
||||
GEB ~func(R) GIOB,
|
||||
GEFAB ~func(R) GIOFAB,
|
||||
GIOA ~func() ET.Either[E, A],
|
||||
GIOB ~func() ET.Either[E, B],
|
||||
GIOFAB ~func() ET.Either[E, func(A) B],
|
||||
R, E, A, B any](fab GEFAB, fa GEA) GEB {
|
||||
|
||||
return eithert.MonadAp(
|
||||
G.MonadAp[GEA, GEB, func(R) func() func(ET.Either[E, A]) ET.Either[E, B], GIOA, GIOB, func() func(ET.Either[E, A]) ET.Either[E, B], R, ET.Either[E, A], ET.Either[E, B]],
|
||||
G.MonadMap[GEFAB, func(R) func() func(ET.Either[E, A]) ET.Either[E, B], GIOFAB, func() func(ET.Either[E, A]) ET.Either[E, B], R, ET.Either[E, func(A) B], func(ET.Either[E, A]) ET.Either[E, B]],
|
||||
fab,
|
||||
fa,
|
||||
)
|
||||
}
|
||||
|
||||
func Ap[
|
||||
GEA ~func(R) GIOA,
|
||||
GEB ~func(R) GIOB,
|
||||
GEFAB ~func(R) GIOFAB,
|
||||
GIOA ~func() ET.Either[E, A],
|
||||
GIOB ~func() ET.Either[E, B],
|
||||
GIOFAB ~func() ET.Either[E, func(A) B],
|
||||
R, E, A, B any](fa GEA) func(fab GEFAB) GEB {
|
||||
return F.Bind2nd(MonadAp[GEA, GEB, GEFAB, GIOA, GIOB, GIOFAB, R, E, A, B], fa)
|
||||
}
|
||||
|
||||
func Right[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R, E, A any](a A) GEA {
|
||||
return eithert.Right(G.Of[GEA, GIOA, R, ET.Either[E, A]], a)
|
||||
}
|
||||
|
||||
func Left[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R, E, A any](e E) GEA {
|
||||
return eithert.Left(G.Of[GEA, GIOA, R, ET.Either[E, A]], e)
|
||||
}
|
||||
|
||||
func ThrowError[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R, E, A any](e E) GEA {
|
||||
return Left[GEA](e)
|
||||
}
|
||||
|
||||
// Of returns a Reader with a fixed value
|
||||
func Of[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R, E, A any](a A) GEA {
|
||||
return Right[GEA](a)
|
||||
}
|
||||
|
||||
func Flatten[GEA ~func(R) GIOA, GGEA ~func(R) GIOEA, GIOA ~func() ET.Either[E, A], GIOEA ~func() ET.Either[E, GEA], R, E, A any](mma GGEA) GEA {
|
||||
return MonadChain(mma, F.Identity[GEA])
|
||||
}
|
||||
|
||||
func FromIOEither[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R, E, A any](t GIOA) GEA {
|
||||
return RD.Of[GEA](t)
|
||||
}
|
||||
|
||||
func FromEither[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R, E, A any](t ET.Either[E, A]) GEA {
|
||||
return G.Of[GEA](t)
|
||||
}
|
||||
|
||||
func RightReader[GA ~func(R) A, GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R, E, A any](ma GA) GEA {
|
||||
return F.Flow2(ma, GIO.Right[GIOA, E, A])
|
||||
}
|
||||
|
||||
func LeftReader[GE ~func(R) E, GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R, E, A any](ma GE) GEA {
|
||||
return F.Flow2(ma, GIO.Left[GIOA, E, A])
|
||||
}
|
||||
|
||||
func FromReader[GA ~func(R) A, GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R, E, A any](ma GA) GEA {
|
||||
return RightReader[GA, GEA](ma)
|
||||
}
|
||||
|
||||
func MonadFromReaderIO[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], GRIO ~func(R) GIO, GIO ~func() A, R, E, A any](a A, f func(A) GRIO) GEA {
|
||||
return F.Pipe2(
|
||||
a,
|
||||
f,
|
||||
RightReaderIO[GEA, GIOA, GRIO, GIO, R, E, A],
|
||||
)
|
||||
}
|
||||
|
||||
func FromReaderIO[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], GRIO ~func(R) GIO, GIO ~func() A, R, E, A any](f func(A) GRIO) func(A) GEA {
|
||||
return F.Bind2nd(MonadFromReaderIO[GEA, GIOA, GRIO, GIO, R, E, A], f)
|
||||
}
|
||||
|
||||
func RightReaderIO[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], GRIO ~func(R) GIO, GIO ~func() A, R, E, A any](ma GRIO) GEA {
|
||||
return eithert.RightF(
|
||||
G.MonadMap[GRIO, GEA, GIO, GIOA, R, A, ET.Either[E, A]],
|
||||
ma,
|
||||
)
|
||||
}
|
||||
|
||||
func LeftReaderIO[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], GRIO ~func(R) GIO, GIO ~func() E, R, E, A any](me GRIO) GEA {
|
||||
return eithert.LeftF(
|
||||
G.MonadMap[GRIO, GEA, GIO, GIOA, R, E, ET.Either[E, A]],
|
||||
me,
|
||||
)
|
||||
}
|
||||
|
||||
func RightIO[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], GR ~func() A, R, E, A any](ma GR) GEA {
|
||||
return F.Pipe2(ma, GIO.RightIO[GIOA, GR, E, A], FromIOEither[GEA, GIOA, R, E, A])
|
||||
}
|
||||
|
||||
func LeftIO[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], GR ~func() E, R, E, A any](ma GR) GEA {
|
||||
return F.Pipe2(ma, GIO.LeftIO[GIOA, GR, E, A], FromIOEither[GEA, GIOA, R, E, A])
|
||||
}
|
||||
|
||||
func FromIO[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], GR ~func() A, R, E, A any](ma GR) GEA {
|
||||
return RightIO[GEA](ma)
|
||||
}
|
||||
|
||||
func FromReaderEither[GA ~func(R) ET.Either[E, A], GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R, E, A any](ma GA) GEA {
|
||||
return F.Flow2(ma, GIO.FromEither[GIOA, E, A])
|
||||
}
|
||||
|
||||
func Ask[GER ~func(R) GIOR, GIOR ~func() ET.Either[E, R], R, E any]() GER {
|
||||
return FR.Ask(FromReader[func(R) R, GER, GIOR, R, E, R])()
|
||||
}
|
||||
|
||||
func Asks[GA ~func(R) A, GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R, E, A any](r GA) GEA {
|
||||
return FR.Asks(FromReader[GA, GEA, GIOA, R, E, A])(r)
|
||||
}
|
||||
|
||||
func FromOption[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R, E, A any](onNone func() E) func(O.Option[A]) GEA {
|
||||
return FE.FromOption(FromEither[GEA, GIOA, R, E, A], onNone)
|
||||
}
|
||||
|
||||
func FromPredicate[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R, E, A any](pred func(A) bool, onFalse func(A) E) func(A) GEA {
|
||||
return FE.FromPredicate(FromEither[GEA, GIOA, R, E, A], pred, onFalse)
|
||||
}
|
||||
|
||||
func Fold[GB ~func(R) GIOB, GEA ~func(R) GIOA, GIOB ~func() B, GIOA ~func() ET.Either[E, A], R, E, A, B any](onLeft func(E) GB, onRight func(A) GB) func(GEA) GB {
|
||||
return eithert.MatchE(G.MonadChain[GEA, GB, GIOA, GIOB, R, ET.Either[E, A], B], onLeft, onRight)
|
||||
}
|
||||
|
||||
func GetOrElse[GA ~func(R) GIOB, GEA ~func(R) GIOA, GIOB ~func() A, GIOA ~func() ET.Either[E, A], R, E, A any](onLeft func(E) GA) func(GEA) GA {
|
||||
return eithert.GetOrElse(G.MonadChain[GEA, GA, GIOA, GIOB, R, ET.Either[E, A], A], G.Of[GA, GIOB, R, A], onLeft)
|
||||
}
|
||||
|
||||
func OrElse[GEA1 ~func(R) GIOA1, GEA2 ~func(R) GIOA2, GIOA1 ~func() ET.Either[E1, A], GIOA2 ~func() ET.Either[E2, A], R, E1, A, E2 any](onLeft func(E1) GEA2) func(GEA1) GEA2 {
|
||||
return eithert.OrElse(G.MonadChain[GEA1, GEA2, GIOA1, GIOA2, R, ET.Either[E1, A], ET.Either[E2, A]], G.Of[GEA2, GIOA2, R, ET.Either[E2, A]], onLeft)
|
||||
}
|
||||
|
||||
func OrLeft[GEA1 ~func(R) GIOA1, GE2 ~func(R) GIOE2, GEA2 ~func(R) GIOA2, GIOA1 ~func() ET.Either[E1, A], GIOE2 ~func() E2, GIOA2 ~func() ET.Either[E2, A], E1, R, E2, A any](onLeft func(E1) GE2) func(GEA1) GEA2 {
|
||||
return eithert.OrLeft(
|
||||
G.MonadChain[GEA1, GEA2, GIOA1, GIOA2, R, ET.Either[E1, A], ET.Either[E2, A]],
|
||||
G.MonadMap[GE2, GEA2, GIOE2, GIOA2, R, E2, ET.Either[E2, A]],
|
||||
G.Of[GEA2, GIOA2, R, ET.Either[E2, A]],
|
||||
onLeft,
|
||||
)
|
||||
}
|
||||
|
||||
func MonadBiMap[GA ~func(R) GE1A, GB ~func(R) GE2B, GE1A ~func() ET.Either[E1, A], GE2B ~func() ET.Either[E2, B], R, E1, E2, A, B any](fa GA, f func(E1) E2, g func(A) B) GB {
|
||||
return eithert.MonadBiMap(G.MonadMap[GA, GB, GE1A, GE2B, R, 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(R) GE1A, GB ~func(R) GE2B, GE1A ~func() ET.Either[E1, A], GE2B ~func() ET.Either[E2, B], R, E1, E2, A, B any](f func(E1) E2, g func(A) B) func(GA) GB {
|
||||
return eithert.BiMap(G.MonadMap[GA, GB, GE1A, GE2B, R, ET.Either[E1, A], ET.Either[E2, B]], f, g)
|
||||
}
|
||||
|
||||
// Swap changes the order of type parameters
|
||||
func Swap[GREA ~func(R) GEA, GRAE ~func(R) GAE, GEA ~func() ET.Either[E, A], GAE ~func() ET.Either[A, E], R, E, A any](val GREA) GRAE {
|
||||
return RD.MonadMap[GREA, GRAE, R, GEA, GAE](val, GIO.Swap[GEA, GAE])
|
||||
}
|
||||
|
||||
// Defer creates an IO by creating a brand new IO via a generator function, each time
|
||||
func Defer[GEA ~func(R) GA, GA ~func() ET.Either[E, A], R, E, A any](gen func() GEA) GEA {
|
||||
return G.Defer[GEA](gen)
|
||||
}
|
||||
|
||||
// TryCatch wraps a reader returning a tuple as an error into ReaderIOEither
|
||||
func TryCatch[GEA ~func(R) GA, GA ~func() ET.Either[E, A], R, E, A any](f func(R) func() (A, error), onThrow func(error) E) GEA {
|
||||
return func(r R) GA {
|
||||
return IOE.TryCatch[GA](f(r), onThrow)
|
||||
}
|
||||
}
|
33
readerioeither/generic/resource.go
Normal file
33
readerioeither/generic/resource.go
Normal file
@ -0,0 +1,33 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
IOE "github.com/ibm/fp-go/ioeither/generic"
|
||||
)
|
||||
|
||||
// WithResource constructs a function that creates a resource, then operates on it and then releases the resource
|
||||
func WithResource[
|
||||
GEA ~func(L) TEA,
|
||||
GER ~func(L) TER,
|
||||
GEANY ~func(L) TEANY,
|
||||
|
||||
TEA ~func() ET.Either[E, A],
|
||||
TER ~func() ET.Either[E, R],
|
||||
TEANY ~func() ET.Either[E, ANY],
|
||||
|
||||
L, E, R, A, ANY any](onCreate GER, onRelease func(R) GEANY) func(func(R) GEA) GEA {
|
||||
|
||||
return func(f func(R) GEA) GEA {
|
||||
return func(l L) TEA {
|
||||
// dispatch to the generic implementation
|
||||
return IOE.WithResource[TEA](
|
||||
onCreate(l),
|
||||
func(r R) TEANY {
|
||||
return onRelease(r)(l)
|
||||
},
|
||||
)(func(r R) TEA {
|
||||
return f(r)(l)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
79
readerioeither/generic/sequence.go
Normal file
79
readerioeither/generic/sequence.go
Normal file
@ -0,0 +1,79 @@
|
||||
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(E) GIOA,
|
||||
GTA ~func(E) GIOTA,
|
||||
GIOA ~func() ET.Either[L, A],
|
||||
GIOTA ~func() ET.Either[L, T.Tuple1[A]],
|
||||
E, L, A any](a GA) GTA {
|
||||
return apply.SequenceT1(
|
||||
Map[GA, GTA, GIOA, GIOTA, E, L, A, T.Tuple1[A]],
|
||||
|
||||
a,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceT2[
|
||||
GA ~func(E) GIOA,
|
||||
GB ~func(E) GIOB,
|
||||
GTAB ~func(E) GIOTAB,
|
||||
GIOA ~func() ET.Either[L, A],
|
||||
GIOB ~func() ET.Either[L, B],
|
||||
GIOTAB ~func() ET.Either[L, T.Tuple2[A, B]],
|
||||
E, L, A, B any](a GA, b GB) GTAB {
|
||||
return apply.SequenceT2(
|
||||
Map[GA, func(E) func() ET.Either[L, func(B) T.Tuple2[A, B]], GIOA, func() ET.Either[L, func(B) T.Tuple2[A, B]], E, L, A, func(B) T.Tuple2[A, B]],
|
||||
Ap[GB, GTAB, func(E) func() ET.Either[L, func(B) T.Tuple2[A, B]], GIOB, GIOTAB, func() ET.Either[L, func(B) T.Tuple2[A, B]], E, L, B, T.Tuple2[A, B]],
|
||||
|
||||
a, b,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceT3[
|
||||
GA ~func(E) GIOA,
|
||||
GB ~func(E) GIOB,
|
||||
GC ~func(E) GIOC,
|
||||
GTABC ~func(E) GIOTABC,
|
||||
GIOA ~func() ET.Either[L, A],
|
||||
GIOB ~func() ET.Either[L, B],
|
||||
GIOC ~func() ET.Either[L, C],
|
||||
GIOTABC ~func() ET.Either[L, T.Tuple3[A, B, C]],
|
||||
E, L, A, B, C any](a GA, b GB, c GC) GTABC {
|
||||
return apply.SequenceT3(
|
||||
Map[GA, func(E) func() ET.Either[L, func(B) func(C) T.Tuple3[A, B, C]], GIOA, func() ET.Either[L, func(B) func(C) T.Tuple3[A, B, C]], E, L, A, func(B) func(C) T.Tuple3[A, B, C]],
|
||||
Ap[GB, func(E) func() ET.Either[L, func(C) T.Tuple3[A, B, C]], func(E) func() ET.Either[L, func(B) func(C) T.Tuple3[A, B, C]], GIOB, func() ET.Either[L, func(C) T.Tuple3[A, B, C]], func() ET.Either[L, func(B) func(C) T.Tuple3[A, B, C]], E, L, B, func(C) T.Tuple3[A, B, C]],
|
||||
Ap[GC, GTABC, func(E) func() ET.Either[L, func(C) T.Tuple3[A, B, C]], GIOC, GIOTABC, func() ET.Either[L, func(C) T.Tuple3[A, B, C]], E, L, C, T.Tuple3[A, B, C]],
|
||||
|
||||
a, b, c,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceT4[
|
||||
GA ~func(E) GIOA,
|
||||
GB ~func(E) GIOB,
|
||||
GC ~func(E) GIOC,
|
||||
GD ~func(E) GIOD,
|
||||
GTABCD ~func(E) GIOTABCD,
|
||||
GIOA ~func() ET.Either[L, A],
|
||||
GIOB ~func() ET.Either[L, B],
|
||||
GIOC ~func() ET.Either[L, C],
|
||||
GIOD ~func() ET.Either[L, D],
|
||||
GIOTABCD ~func() ET.Either[L, T.Tuple4[A, B, C, D]],
|
||||
E, L, A, B, C, D any](a GA, b GB, c GC, d GD) GTABCD {
|
||||
return apply.SequenceT4(
|
||||
Map[GA, func(E) func() ET.Either[L, func(B) func(C) func(D) T.Tuple4[A, B, C, D]], GIOA, func() ET.Either[L, func(B) func(C) func(D) T.Tuple4[A, B, C, D]], E, L, A, func(B) func(C) func(D) T.Tuple4[A, B, C, D]],
|
||||
Ap[GB, func(E) func() ET.Either[L, func(C) func(D) T.Tuple4[A, B, C, D]], func(E) func() ET.Either[L, func(B) func(C) func(D) T.Tuple4[A, B, C, D]], GIOB, func() ET.Either[L, func(C) func(D) T.Tuple4[A, B, C, D]], func() ET.Either[L, func(B) func(C) func(D) T.Tuple4[A, B, C, D]], E, L, B, func(C) func(D) T.Tuple4[A, B, C, D]],
|
||||
Ap[GC, func(E) func() ET.Either[L, func(D) T.Tuple4[A, B, C, D]], func(E) func() ET.Either[L, func(C) func(D) T.Tuple4[A, B, C, D]], GIOC, func() ET.Either[L, func(D) T.Tuple4[A, B, C, D]], func() ET.Either[L, func(C) func(D) T.Tuple4[A, B, C, D]], E, L, C, func(D) T.Tuple4[A, B, C, D]],
|
||||
Ap[GD, GTABCD, func(E) func() ET.Either[L, func(D) T.Tuple4[A, B, C, D]], GIOD, GIOTABCD, func() ET.Either[L, func(D) T.Tuple4[A, B, C, D]], E, L, D, T.Tuple4[A, B, C, D]],
|
||||
|
||||
a, b, c, d,
|
||||
)
|
||||
}
|
63
readerioeither/generic/traverse.go
Normal file
63
readerioeither/generic/traverse.go
Normal file
@ -0,0 +1,63 @@
|
||||
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(E) GIOB, GBS ~func(E) GIOBS, GIOB ~func() ET.Either[L, B], GIOBS ~func() ET.Either[L, BBS], AAS ~[]A, BBS ~[]B, E, L, A, B any](ma AAS, f func(A) GB) GBS {
|
||||
return RA.MonadTraverse[AAS](
|
||||
Of[GBS, GIOBS, E, L, BBS],
|
||||
Map[GBS, func(E) func() ET.Either[L, func(B) BBS], GIOBS, func() ET.Either[L, func(B) BBS], E, L, BBS, func(B) BBS],
|
||||
Ap[GB, GBS, func(E) func() ET.Either[L, func(B) BBS], GIOB, GIOBS, func() ET.Either[L, func(B) BBS], E, L, B, BBS],
|
||||
|
||||
ma, f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func TraverseArray[GB ~func(E) GIOB, GBS ~func(E) GIOBS, GIOB ~func() ET.Either[L, B], GIOBS ~func() ET.Either[L, BBS], AAS ~[]A, BBS ~[]B, E, L, A, B any](f func(A) GB) func(AAS) GBS {
|
||||
return RA.Traverse[AAS](
|
||||
Of[GBS, GIOBS, E, L, BBS],
|
||||
Map[GBS, func(E) func() ET.Either[L, func(B) BBS], GIOBS, func() ET.Either[L, func(B) BBS], E, L, BBS, func(B) BBS],
|
||||
Ap[GB, GBS, func(E) func() ET.Either[L, func(B) BBS], GIOB, GIOBS, func() ET.Either[L, func(B) BBS], E, L, B, BBS],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArray[GA ~func(E) GIOA, GAS ~func(E) GIOAS, GIOA ~func() ET.Either[L, A], GIOAS ~func() ET.Either[L, AAS], AAS ~[]A, GAAS ~[]GA, E, L, A any](ma GAAS) GAS {
|
||||
return MonadTraverseArray[GA, GAS](ma, F.Identity[GA])
|
||||
}
|
||||
|
||||
// MonadTraverseRecord transforms an array
|
||||
func MonadTraverseRecord[GB ~func(C) GIOB, GBS ~func(C) GIOBS, GIOB ~func() ET.Either[E, B], GIOBS ~func() ET.Either[E, BBS], AAS ~map[K]A, BBS ~map[K]B, K comparable, C, E, A, B any](tas AAS, f func(A) GB) GBS {
|
||||
return RR.MonadTraverse[AAS](
|
||||
Of[GBS, GIOBS, C, E, BBS],
|
||||
Map[GBS, func(C) func() ET.Either[E, func(B) BBS], GIOBS, func() ET.Either[E, func(B) BBS], C, E, BBS, func(B) BBS],
|
||||
Ap[GB, GBS, func(C) func() ET.Either[E, func(B) BBS], GIOB, GIOBS, func() ET.Either[E, func(B) BBS], C, E, B, BBS],
|
||||
|
||||
tas,
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseRecord transforms an array
|
||||
func TraverseRecord[GB ~func(C) GIOB, GBS ~func(C) GIOBS, GIOB ~func() ET.Either[E, B], GIOBS ~func() ET.Either[E, BBS], AAS ~map[K]A, BBS ~map[K]B, K comparable, C, E, A, B any](f func(A) GB) func(AAS) GBS {
|
||||
return RR.Traverse[AAS](
|
||||
Of[GBS, GIOBS, C, E, BBS],
|
||||
Map[GBS, func(C) func() ET.Either[E, func(B) BBS], GIOBS, func() ET.Either[E, func(B) BBS], C, E, BBS, func(B) BBS],
|
||||
Ap[GB, GBS, func(C) func() ET.Either[E, func(B) BBS], GIOB, GIOBS, func() ET.Either[E, func(B) BBS], C, E, B, BBS],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// SequenceRecord converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceRecord[GA ~func(C) GIOA, GAS ~func(C) GIOAS, GIOA ~func() ET.Either[E, A], GIOAS ~func() ET.Either[E, AAS], AAS ~map[K]A, GAAS ~map[K]GA, K comparable, C, E, A any](tas GAAS) GAS {
|
||||
return MonadTraverseRecord[GA, GAS](tas, F.Identity[GA])
|
||||
}
|
216
readerioeither/reader.go
Normal file
216
readerioeither/reader.go
Normal file
@ -0,0 +1,216 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
"github.com/ibm/fp-go/io"
|
||||
IOE "github.com/ibm/fp-go/ioeither"
|
||||
O "github.com/ibm/fp-go/option"
|
||||
RD "github.com/ibm/fp-go/reader"
|
||||
RE "github.com/ibm/fp-go/readereither"
|
||||
RIO "github.com/ibm/fp-go/readerio"
|
||||
G "github.com/ibm/fp-go/readerioeither/generic"
|
||||
)
|
||||
|
||||
type ReaderIOEither[R, E, A any] RD.Reader[R, IOE.IOEither[E, A]]
|
||||
|
||||
// MakeReader constructs an instance of a reader
|
||||
func MakeReader[R, E, A any](f func(R) IOE.IOEither[E, A]) ReaderIOEither[R, E, A] {
|
||||
return G.MakeReader[ReaderIOEither[R, E, A]](f)
|
||||
}
|
||||
|
||||
func MonadFromReaderIO[R, E, A any](a A, f func(A) RIO.ReaderIO[R, A]) ReaderIOEither[R, E, A] {
|
||||
return G.MonadFromReaderIO[ReaderIOEither[R, E, A]](a, f)
|
||||
}
|
||||
|
||||
func FromReaderIO[R, E, A any](f func(A) RIO.ReaderIO[R, A]) func(A) ReaderIOEither[R, E, A] {
|
||||
return G.FromReaderIO[ReaderIOEither[R, E, A]](f)
|
||||
}
|
||||
|
||||
func RightReaderIO[R, E, A any](ma RIO.ReaderIO[R, A]) ReaderIOEither[R, E, A] {
|
||||
return G.RightReaderIO[ReaderIOEither[R, E, A]](ma)
|
||||
}
|
||||
|
||||
func LeftReaderIO[R, E, A any](me RIO.ReaderIO[R, E]) ReaderIOEither[R, E, A] {
|
||||
return G.LeftReaderIO[ReaderIOEither[R, E, A]](me)
|
||||
}
|
||||
|
||||
func MonadMap[R, E, A, B any](fa ReaderIOEither[R, E, A], f func(A) B) ReaderIOEither[R, E, B] {
|
||||
return G.MonadMap[ReaderIOEither[R, E, A], ReaderIOEither[R, E, B]](fa, f)
|
||||
}
|
||||
|
||||
func Map[R, E, A, B any](f func(A) B) func(fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B] {
|
||||
return G.Map[ReaderIOEither[R, E, A], ReaderIOEither[R, E, B]](f)
|
||||
}
|
||||
|
||||
func MonadMapTo[R, E, A, B any](fa ReaderIOEither[R, E, A], b B) ReaderIOEither[R, E, B] {
|
||||
return G.MonadMapTo[ReaderIOEither[R, E, A], ReaderIOEither[R, E, B]](fa, b)
|
||||
}
|
||||
|
||||
func MapTo[R, E, A, B any](b B) func(ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B] {
|
||||
return G.MapTo[ReaderIOEither[R, E, A], ReaderIOEither[R, E, B]](b)
|
||||
}
|
||||
|
||||
func MonadChain[R, E, A, B any](fa ReaderIOEither[R, E, A], f func(A) ReaderIOEither[R, E, B]) ReaderIOEither[R, E, B] {
|
||||
return G.MonadChain(fa, f)
|
||||
}
|
||||
|
||||
func MonadChainEitherK[R, E, A, B any](ma ReaderIOEither[R, E, A], f func(A) ET.Either[E, B]) ReaderIOEither[R, E, B] {
|
||||
return G.MonadChainEitherK[ReaderIOEither[R, E, A], ReaderIOEither[R, E, B]](ma, f)
|
||||
}
|
||||
|
||||
func ChainEitherK[R, E, A, B any](f func(A) ET.Either[E, B]) func(ma ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B] {
|
||||
return G.ChainEitherK[ReaderIOEither[R, E, A], ReaderIOEither[R, E, B]](f)
|
||||
}
|
||||
|
||||
func MonadChainReaderK[R, E, A, B any](ma ReaderIOEither[R, E, A], f func(A) RD.Reader[R, B]) ReaderIOEither[R, E, B] {
|
||||
return G.MonadChainReaderK[ReaderIOEither[R, E, A], ReaderIOEither[R, E, B]](ma, f)
|
||||
}
|
||||
|
||||
func ChainReaderK[R, E, A, B any](f func(A) RD.Reader[R, B]) func(ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B] {
|
||||
return G.ChainReaderK[ReaderIOEither[R, E, A], ReaderIOEither[R, E, B]](f)
|
||||
}
|
||||
|
||||
func MonadChainIOEitherK[R, E, A, B any](ma ReaderIOEither[R, E, A], f func(A) IOE.IOEither[E, B]) ReaderIOEither[R, E, B] {
|
||||
return G.MonadChainIOEitherK[ReaderIOEither[R, E, A], ReaderIOEither[R, E, B]](ma, f)
|
||||
}
|
||||
|
||||
func ChainIOEitherK[R, E, A, B any](f func(A) IOE.IOEither[E, B]) func(ma ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B] {
|
||||
return G.ChainIOEitherK[ReaderIOEither[R, E, A], ReaderIOEither[R, E, B]](f)
|
||||
}
|
||||
|
||||
func MonadChainIOK[R, E, A, B any](ma ReaderIOEither[R, E, A], f func(A) io.IO[B]) ReaderIOEither[R, E, B] {
|
||||
return G.MonadChainIOK[ReaderIOEither[R, E, A], ReaderIOEither[R, E, B]](ma, f)
|
||||
}
|
||||
|
||||
func ChainIOK[R, E, A, B any](f func(A) io.IO[B]) func(ma ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B] {
|
||||
return G.ChainIOK[ReaderIOEither[R, E, A], ReaderIOEither[R, E, B]](f)
|
||||
}
|
||||
|
||||
func ChainOptionK[R, E, A, B any](onNone func() E) func(func(A) O.Option[B]) func(ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B] {
|
||||
return G.ChainOptionK[ReaderIOEither[R, E, A], ReaderIOEither[R, E, B]](onNone)
|
||||
}
|
||||
|
||||
func MonadAp[R, E, A, B any](fab ReaderIOEither[R, E, func(A) B], fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B] {
|
||||
return G.MonadAp[ReaderIOEither[R, E, A], ReaderIOEither[R, E, B]](fab, fa)
|
||||
}
|
||||
|
||||
func Ap[R, E, A, B any](fa ReaderIOEither[R, E, A]) func(fab ReaderIOEither[R, E, func(A) B]) ReaderIOEither[R, E, B] {
|
||||
return G.Ap[ReaderIOEither[R, E, A], ReaderIOEither[R, E, B], ReaderIOEither[R, E, func(A) B]](fa)
|
||||
}
|
||||
|
||||
func Chain[R, E, A, B any](f func(A) ReaderIOEither[R, E, B]) func(fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B] {
|
||||
return G.Chain[ReaderIOEither[R, E, A]](f)
|
||||
}
|
||||
|
||||
func Right[R, E, A any](a A) ReaderIOEither[R, E, A] {
|
||||
return G.Right[ReaderIOEither[R, E, A]](a)
|
||||
}
|
||||
|
||||
func Left[R, E, A any](e E) ReaderIOEither[R, E, A] {
|
||||
return G.Left[ReaderIOEither[R, E, A]](e)
|
||||
}
|
||||
|
||||
func ThrowError[R, E, A any](e E) ReaderIOEither[R, E, A] {
|
||||
return G.ThrowError[ReaderIOEither[R, E, A]](e)
|
||||
}
|
||||
|
||||
// Of returns a Reader with a fixed value
|
||||
func Of[R, E, A any](a A) ReaderIOEither[R, E, A] {
|
||||
return G.Of[ReaderIOEither[R, E, A]](a)
|
||||
}
|
||||
|
||||
func Flatten[R, E, A any](mma ReaderIOEither[R, E, ReaderIOEither[R, E, A]]) ReaderIOEither[R, E, A] {
|
||||
return G.Flatten(mma)
|
||||
}
|
||||
|
||||
func FromEither[R, E, A any](t ET.Either[E, A]) ReaderIOEither[R, E, A] {
|
||||
return G.FromEither[ReaderIOEither[R, E, A]](t)
|
||||
}
|
||||
|
||||
func RightReader[R, E, A any](ma RD.Reader[R, A]) ReaderIOEither[R, E, A] {
|
||||
return G.RightReader[RD.Reader[R, A], ReaderIOEither[R, E, A]](ma)
|
||||
}
|
||||
|
||||
func LeftReader[R, E, A any](ma RD.Reader[R, E]) ReaderIOEither[R, E, A] {
|
||||
return G.LeftReader[RD.Reader[R, E], ReaderIOEither[R, E, A]](ma)
|
||||
}
|
||||
|
||||
func FromReader[R, E, A any](ma RD.Reader[R, A]) ReaderIOEither[R, E, A] {
|
||||
return G.FromReader[RD.Reader[R, A], ReaderIOEither[R, E, A]](ma)
|
||||
}
|
||||
|
||||
func RightIO[R, E, A any](ma io.IO[A]) ReaderIOEither[R, E, A] {
|
||||
return G.RightIO[ReaderIOEither[R, E, A]](ma)
|
||||
}
|
||||
|
||||
func LeftIO[R, E, A any](ma io.IO[E]) ReaderIOEither[R, E, A] {
|
||||
return G.LeftIO[ReaderIOEither[R, E, A]](ma)
|
||||
}
|
||||
|
||||
func FromIO[R, E, A any](ma io.IO[A]) ReaderIOEither[R, E, A] {
|
||||
return G.FromIO[ReaderIOEither[R, E, A]](ma)
|
||||
}
|
||||
|
||||
func FromIOEither[R, E, A any](ma IOE.IOEither[E, A]) ReaderIOEither[R, E, A] {
|
||||
return G.FromIOEither[ReaderIOEither[R, E, A]](ma)
|
||||
}
|
||||
|
||||
func FromReaderEither[R, E, A any](ma RE.ReaderEither[R, E, A]) ReaderIOEither[R, E, A] {
|
||||
return G.FromReaderEither[RE.ReaderEither[R, E, A], ReaderIOEither[R, E, A]](ma)
|
||||
}
|
||||
|
||||
func Ask[R, E any]() ReaderIOEither[R, E, R] {
|
||||
return G.Ask[ReaderIOEither[R, E, R]]()
|
||||
}
|
||||
|
||||
func Asks[R, E, A any](r RD.Reader[R, A]) ReaderIOEither[R, E, A] {
|
||||
return G.Asks[RD.Reader[R, A], ReaderIOEither[R, E, A]](r)
|
||||
}
|
||||
|
||||
func FromOption[R, E, A any](onNone func() E) func(O.Option[A]) ReaderIOEither[R, E, A] {
|
||||
return G.FromOption[ReaderIOEither[R, E, A]](onNone)
|
||||
}
|
||||
|
||||
func FromPredicate[R, E, A any](pred func(A) bool, onFalse func(A) E) func(A) ReaderIOEither[R, E, A] {
|
||||
return G.FromPredicate[ReaderIOEither[R, E, A]](pred, onFalse)
|
||||
}
|
||||
|
||||
func Fold[R, E, A, B any](onLeft func(E) RIO.ReaderIO[R, B], onRight func(A) RIO.ReaderIO[R, B]) func(ReaderIOEither[R, E, A]) RIO.ReaderIO[R, B] {
|
||||
return G.Fold[RIO.ReaderIO[R, B], ReaderIOEither[R, E, A]](onLeft, onRight)
|
||||
}
|
||||
|
||||
func GetOrElse[R, E, A any](onLeft func(E) RIO.ReaderIO[R, A]) func(ReaderIOEither[R, E, A]) RIO.ReaderIO[R, A] {
|
||||
return G.GetOrElse[RIO.ReaderIO[R, A], ReaderIOEither[R, E, A]](onLeft)
|
||||
}
|
||||
|
||||
func OrElse[R, E1, A, E2 any](onLeft func(E1) ReaderIOEither[R, E2, A]) func(ReaderIOEither[R, E1, A]) ReaderIOEither[R, E2, A] {
|
||||
return G.OrElse[ReaderIOEither[R, E1, A]](onLeft)
|
||||
}
|
||||
|
||||
func OrLeft[E1, R, E2, A any](onLeft func(E1) RIO.ReaderIO[R, E2]) func(ReaderIOEither[R, E1, A]) ReaderIOEither[R, E2, A] {
|
||||
return G.OrLeft[ReaderIOEither[R, E1, A], RIO.ReaderIO[R, E2], ReaderIOEither[R, E2, A]](onLeft)
|
||||
}
|
||||
|
||||
func MonadBiMap[R, E1, E2, A, B any](fa ReaderIOEither[R, E1, A], f func(E1) E2, g func(A) B) ReaderIOEither[R, E2, B] {
|
||||
return G.MonadBiMap[ReaderIOEither[R, E1, A], ReaderIOEither[R, E2, B]](fa, f, g)
|
||||
}
|
||||
|
||||
// BiMap maps a pair of functions over the two type arguments of the bifunctor.
|
||||
func BiMap[R, E1, E2, A, B any](f func(E1) E2, g func(A) B) func(ReaderIOEither[R, E1, A]) ReaderIOEither[R, E2, B] {
|
||||
return G.BiMap[ReaderIOEither[R, E1, A], ReaderIOEither[R, E2, B]](f, g)
|
||||
}
|
||||
|
||||
// Swap changes the order of type parameters
|
||||
func Swap[R, E, A any](val ReaderIOEither[R, E, A]) ReaderIOEither[R, A, E] {
|
||||
return G.Swap[ReaderIOEither[R, E, A], ReaderIOEither[R, A, E]](val)
|
||||
}
|
||||
|
||||
// Defer creates an IO by creating a brand new IO via a generator function, each time
|
||||
func Defer[R, E, A any](gen func() ReaderIOEither[R, E, A]) ReaderIOEither[R, E, A] {
|
||||
return G.Defer[ReaderIOEither[R, E, A]](gen)
|
||||
}
|
||||
|
||||
// TryCatch wraps a reader returning a tuple as an error into ReaderIOEither
|
||||
func TryCatch[R, E, A any](f func(R) func() (A, error), onThrow func(error) E) ReaderIOEither[R, E, A] {
|
||||
return G.TryCatch[ReaderIOEither[R, E, A]](f, onThrow)
|
||||
}
|
64
readerioeither/reader_test.go
Normal file
64
readerioeither/reader_test.go
Normal file
@ -0,0 +1,64 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
E "github.com/ibm/fp-go/either"
|
||||
F "github.com/ibm/fp-go/function"
|
||||
"github.com/ibm/fp-go/internal/utils"
|
||||
R "github.com/ibm/fp-go/reader"
|
||||
RIO "github.com/ibm/fp-go/readerio"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMap(t *testing.T) {
|
||||
|
||||
g := F.Pipe1(
|
||||
Of[context.Context, error](1),
|
||||
Map[context.Context, error](utils.Double),
|
||||
)
|
||||
|
||||
assert.Equal(t, E.Of[error](2), g(context.Background())())
|
||||
}
|
||||
|
||||
func TestOrLeft(t *testing.T) {
|
||||
f := OrLeft[string, context.Context, string, int](func(s string) RIO.ReaderIO[context.Context, string] {
|
||||
return RIO.Of[context.Context](s + "!")
|
||||
})
|
||||
|
||||
g1 := F.Pipe1(
|
||||
Right[context.Context, string](1),
|
||||
f,
|
||||
)
|
||||
|
||||
g2 := F.Pipe1(
|
||||
Left[context.Context, string, int]("a"),
|
||||
f,
|
||||
)
|
||||
|
||||
assert.Equal(t, E.Of[string](1), g1(context.Background())())
|
||||
assert.Equal(t, E.Left[int]("a!"), g2(context.Background())())
|
||||
}
|
||||
|
||||
func TestAp(t *testing.T) {
|
||||
g := F.Pipe1(
|
||||
Right[context.Context, error](utils.Double),
|
||||
Ap[context.Context, error, int, int](Right[context.Context, error](1)),
|
||||
)
|
||||
|
||||
assert.Equal(t, E.Right[error](2), g(context.Background())())
|
||||
}
|
||||
|
||||
func TestChainReaderK(t *testing.T) {
|
||||
|
||||
g := F.Pipe1(
|
||||
Of[context.Context, error](1),
|
||||
ChainReaderK[context.Context, error](func(v int) R.Reader[context.Context, string] {
|
||||
return R.Of[context.Context](fmt.Sprintf("%d", v))
|
||||
}),
|
||||
)
|
||||
|
||||
assert.Equal(t, E.Right[error]("1"), g(context.Background())())
|
||||
}
|
10
readerioeither/resource.go
Normal file
10
readerioeither/resource.go
Normal file
@ -0,0 +1,10 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/readerioeither/generic"
|
||||
)
|
||||
|
||||
// WithResource constructs a function that creates a resource, then operates on it and then releases the resource
|
||||
func WithResource[L, E, R, A any](onCreate ReaderIOEither[L, E, R], onRelease func(R) ReaderIOEither[L, E, any]) func(func(R) ReaderIOEither[L, E, A]) ReaderIOEither[L, E, A] {
|
||||
return G.WithResource[ReaderIOEither[L, E, A]](onCreate, onRelease)
|
||||
}
|
42
readerioeither/sequence.go
Normal file
42
readerioeither/sequence.go
Normal file
@ -0,0 +1,42 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/readerioeither/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[R, E, A any](a ReaderIOEither[R, E, A]) ReaderIOEither[R, E, T.Tuple1[A]] {
|
||||
return G.SequenceT1[
|
||||
ReaderIOEither[R, E, A],
|
||||
ReaderIOEither[R, E, T.Tuple1[A]],
|
||||
](a)
|
||||
}
|
||||
|
||||
func SequenceT2[R, E, A, B any](a ReaderIOEither[R, E, A], b ReaderIOEither[R, E, B]) ReaderIOEither[R, E, T.Tuple2[A, B]] {
|
||||
return G.SequenceT2[
|
||||
ReaderIOEither[R, E, A],
|
||||
ReaderIOEither[R, E, B],
|
||||
ReaderIOEither[R, E, T.Tuple2[A, B]],
|
||||
](a, b)
|
||||
}
|
||||
|
||||
func SequenceT3[R, E, A, B, C any](a ReaderIOEither[R, E, A], b ReaderIOEither[R, E, B], c ReaderIOEither[R, E, C]) ReaderIOEither[R, E, T.Tuple3[A, B, C]] {
|
||||
return G.SequenceT3[
|
||||
ReaderIOEither[R, E, A],
|
||||
ReaderIOEither[R, E, B],
|
||||
ReaderIOEither[R, E, C],
|
||||
ReaderIOEither[R, E, T.Tuple3[A, B, C]],
|
||||
](a, b, c)
|
||||
}
|
||||
|
||||
func SequenceT4[R, E, A, B, C, D any](a ReaderIOEither[R, E, A], b ReaderIOEither[R, E, B], c ReaderIOEither[R, E, C], d ReaderIOEither[R, E, D]) ReaderIOEither[R, E, T.Tuple4[A, B, C, D]] {
|
||||
return G.SequenceT4[
|
||||
ReaderIOEither[R, E, A],
|
||||
ReaderIOEither[R, E, B],
|
||||
ReaderIOEither[R, E, C],
|
||||
ReaderIOEither[R, E, D],
|
||||
ReaderIOEither[R, E, T.Tuple4[A, B, C, D]],
|
||||
](a, b, c, d)
|
||||
}
|
23
readerioeither/sequence_test.go
Normal file
23
readerioeither/sequence_test.go
Normal file
@ -0,0 +1,23 @@
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
ET "github.com/ibm/fp-go/either"
|
||||
T "github.com/ibm/fp-go/tuple"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSequence2(t *testing.T) {
|
||||
// two readers of heterogeneous types
|
||||
first := Of[context.Context, error]("a")
|
||||
second := Of[context.Context, error](1)
|
||||
|
||||
// compose
|
||||
s2 := SequenceT2[context.Context, error, string, int]
|
||||
res := s2(first, second)
|
||||
|
||||
ctx := context.Background()
|
||||
assert.Equal(t, ET.Right[error](T.MakeTuple2("a", 1)), res(ctx)())
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user