mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-10 22:31:32 +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:
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))
|
||||
}
|
Reference in New Issue
Block a user