Documentation
¶
Index ¶
- func Ap[B, E, L, A any](fa ReaderEither[E, L, A]) func(ReaderEither[E, L, func(A) B]) ReaderEither[E, L, B]
- func ApS[R, E, S1, S2, T any](setter func(T) func(S1) S2, fa ReaderEither[R, E, T]) func(ReaderEither[R, E, S1]) ReaderEither[R, E, S2]
- func ApSL[R, E, S, T any](lens L.Lens[S, T], fa ReaderEither[R, E, T]) func(ReaderEither[R, E, S]) ReaderEither[R, E, S]
- 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]
- func Bind[R, E, S1, S2, T any](setter func(T) func(S1) S2, f func(S1) ReaderEither[R, E, T]) func(ReaderEither[R, E, S1]) ReaderEither[R, E, S2]
- func BindEitherK[R, E, S1, S2, T any](setter func(T) func(S1) S2, f func(S1) Either[E, T]) func(ReaderEither[R, E, S1]) ReaderEither[R, E, S2]
- func BindL[R, E, S, T any](lens L.Lens[S, T], f func(T) ReaderEither[R, E, T]) func(ReaderEither[R, E, S]) ReaderEither[R, E, S]
- func BindReaderK[R, E, S1, S2, T any](setter func(T) func(S1) S2, f func(S1) Reader[R, T]) func(ReaderEither[R, E, S1]) ReaderEither[R, E, S2]
- func BindTo[R, E, S1, T any](setter func(T) S1) func(ReaderEither[R, E, T]) ReaderEither[R, E, S1]
- func BindToEither[R, E, S1, T any](setter func(T) S1) func(ET.Either[E, T]) ReaderEither[R, E, S1]
- func BindToReader[R, E, S1, T any](setter func(T) S1) func(Reader[R, T]) ReaderEither[R, E, S1]
- func Chain[E, L, A, B any](f func(A) ReaderEither[E, L, B]) func(ReaderEither[E, L, A]) ReaderEither[E, L, B]
- func ChainEitherK[E, L, A, B any](f func(A) Either[L, B]) func(ma ReaderEither[E, L, A]) ReaderEither[E, L, B]
- func ChainOptionK[E, A, B, L any](onNone func() L) func(func(A) Option[B]) func(ReaderEither[E, L, A]) ReaderEither[E, L, B]
- func ChainReaderK[L, E, A, B any](f reader.Kleisli[E, A, B]) func(ReaderEither[E, L, A]) ReaderEither[E, L, B]
- func Curry1[R, T1, A any](f func(R, T1) (A, error)) func(T1) ReaderEither[R, error, A]
- func Curry2[R, T1, T2, A any](f func(R, T1, T2) (A, error)) func(T1) func(T2) ReaderEither[R, error, A]
- 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]
- func Flap[L, E, B, A any](a A) func(ReaderEither[L, E, func(A) B]) ReaderEither[L, E, B]
- func Fold[E, L, A, B any](onLeft func(L) Reader[E, B], onRight func(A) Reader[E, B]) func(ReaderEither[E, L, A]) Reader[E, B]
- func From0[R, A any](f func(R) (A, error)) func() ReaderEither[R, error, A]
- func From1[R, T1, A any](f func(R, T1) (A, error)) func(T1) ReaderEither[R, error, A]
- func From2[R, T1, T2, A any](f func(R, T1, T2) (A, error)) func(T1, T2) ReaderEither[R, error, A]
- func From3[R, T1, T2, T3, A any](f func(R, T1, T2, T3) (A, error)) func(T1, T2, T3) ReaderEither[R, error, A]
- func FromPredicate[E, L, A any](pred func(A) bool, onFalse func(A) L) func(A) ReaderEither[E, L, A]
- func GetOrElse[E, L, A any](onLeft func(L) Reader[E, A]) func(ReaderEither[E, L, A]) Reader[E, A]
- func Let[R, E, S1, S2, T any](setter func(T) func(S1) S2, f func(S1) T) func(ReaderEither[R, E, S1]) ReaderEither[R, E, S2]
- func LetL[R, E, S, T any](lens L.Lens[S, T], f func(T) T) func(ReaderEither[R, E, S]) ReaderEither[R, E, S]
- func LetTo[R, E, S1, S2, T any](setter func(T) func(S1) S2, b T) func(ReaderEither[R, E, S1]) ReaderEither[R, E, S2]
- func LetToL[R, E, S, T any](lens L.Lens[S, T], b T) func(ReaderEither[R, E, S]) ReaderEither[R, E, S]
- func Local[E, A, R2, R1 any](f func(R2) R1) func(ReaderEither[R1, E, A]) ReaderEither[R2, E, A]
- func Map[E, L, A, B any](f func(A) B) func(ReaderEither[E, L, A]) ReaderEither[E, L, B]
- func MapLeft[C, E1, E2, A any](f func(E1) E2) func(ReaderEither[C, E1, A]) ReaderEither[C, E2, A]
- func OrElse[E, L1, A, L2 any](onLeft func(L1) ReaderEither[E, L2, A]) func(ReaderEither[E, L1, A]) ReaderEither[E, L2, A]
- func OrLeft[A, L1, E, L2 any](onLeft func(L1) Reader[E, L2]) func(ReaderEither[E, L1, A]) ReaderEither[E, L2, A]
- func Read[E1, A, E any](e E) func(ReaderEither[E, E1, A]) Either[E1, A]
- func Traverse[R2, R1, E, A, B any](f Kleisli[R1, E, A, B]) func(ReaderEither[R2, E, A]) Kleisli[R2, E, R1, B]
- func TraverseArray[E, L, A, B any](f func(A) ReaderEither[E, L, B]) func([]A) ReaderEither[E, L, []B]
- func TraverseArrayWithIndex[E, L, A, B any](f func(int, A) ReaderEither[E, L, B]) func([]A) ReaderEither[E, L, []B]
- func TraverseReader[R2, R1, E, A, B any](f reader.Kleisli[R1, A, B]) func(ReaderEither[R2, E, A]) Kleisli[R2, E, R1, B]
- func Uncurry1[R, T1, A any](f func(T1) ReaderEither[R, error, A]) func(R, T1) (A, error)
- func Uncurry2[R, T1, T2, A any](f func(T1) func(T2) ReaderEither[R, error, A]) func(R, T1, T2) (A, error)
- 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)
- type Either
- type Kleisli
- type Operator
- type Option
- type Reader
- type ReaderEither
- func Ask[E, L any]() ReaderEither[E, L, E]
- func Asks[L, E, A any](r Reader[E, A]) ReaderEither[E, L, A]
- func Curry0[R, A any](f func(R) (A, error)) ReaderEither[R, error, A]
- func Do[R, E, S any](empty S) ReaderEither[R, E, S]
- func Flatten[E, L, A any](mma ReaderEither[E, L, ReaderEither[E, L, A]]) ReaderEither[E, L, A]
- func FromEither[E, L, A any](e Either[L, A]) ReaderEither[E, L, A]
- func FromReader[L, E, A any](r Reader[E, A]) ReaderEither[E, L, A]
- func Left[E, A, L any](l L) ReaderEither[E, L, A]
- func LeftReader[A, E, L any](l Reader[E, L]) ReaderEither[E, L, A]
- func MonadAp[B, E, L, A any](fab ReaderEither[E, L, func(A) B], fa ReaderEither[E, L, A]) ReaderEither[E, L, B]
- 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]
- func MonadChain[E, L, A, B any](ma ReaderEither[E, L, A], f func(A) ReaderEither[E, L, B]) ReaderEither[E, L, B]
- func MonadChainEitherK[E, L, A, B any](ma ReaderEither[E, L, A], f func(A) Either[L, B]) ReaderEither[E, L, B]
- func MonadChainReaderK[L, E, A, B any](ma ReaderEither[E, L, A], f reader.Kleisli[E, A, B]) ReaderEither[E, L, B]
- func MonadFlap[L, E, A, B any](fab ReaderEither[L, E, func(A) B], a A) ReaderEither[L, E, B]
- func MonadMap[E, L, A, B any](fa ReaderEither[E, L, A], f func(A) B) ReaderEither[E, L, B]
- func MonadMapLeft[C, E1, E2, A any](fa ReaderEither[C, E1, A], f func(E1) E2) ReaderEither[C, E2, A]
- func Of[E, L, A any](a A) ReaderEither[E, L, A]
- func Right[E, L, A any](r A) ReaderEither[E, L, A]
- func RightReader[L, E, A any](r Reader[E, A]) ReaderEither[E, L, A]
- func SequenceArray[E, L, A any](ma []ReaderEither[E, L, A]) ReaderEither[E, L, []A]
- func SequenceT1[L, E, A any](a ReaderEither[E, L, A]) ReaderEither[E, L, T.Tuple1[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]]
- 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]]
- func SequenceT4[L, E, A, B, C, D any](a ReaderEither[E, L, A], b ReaderEither[E, L, B], c ReaderEither[E, L, C], ...) ReaderEither[E, L, T.Tuple4[A, B, C, D]]
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Ap ¶
func Ap[B, E, L, A any](fa ReaderEither[E, L, A]) func(ReaderEither[E, L, func(A) B]) ReaderEither[E, L, B]
func ApS ¶
func ApS[R, E, S1, S2, T any]( setter func(T) func(S1) S2, fa ReaderEither[R, E, T], ) func(ReaderEither[R, E, S1]) ReaderEither[R, E, S2]
ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently (using Applicative rather than Monad). This allows independent computations to be combined without one depending on the result of the other.
Unlike Bind, which sequences operations, ApS can be used when operations are independent and can conceptually run in parallel.
Example:
type State struct {
User User
Config Config
}
type Env struct {
UserService UserService
ConfigService ConfigService
}
// These operations are independent and can be combined with ApS
getUser := readereither.Asks(func(env Env) either.Either[error, User] {
return env.UserService.GetUser()
})
getConfig := readereither.Asks(func(env Env) either.Either[error, Config] {
return env.ConfigService.GetConfig()
})
result := F.Pipe2(
readereither.Do[Env, error](State{}),
readereither.ApS(
func(user User) func(State) State {
return func(s State) State { s.User = user; return s }
},
getUser,
),
readereither.ApS(
func(cfg Config) func(State) State {
return func(s State) State { s.Config = cfg; return s }
},
getConfig,
),
)
func ApSL ¶
func ApSL[R, E, S, T any]( lens L.Lens[S, T], fa ReaderEither[R, E, T], ) func(ReaderEither[R, E, S]) ReaderEither[R, E, S]
ApSL attaches a value to a context using a lens-based setter. This is a convenience function that combines ApS with a lens, allowing you to use optics to update nested structures in a more composable way.
The lens parameter provides both the getter and setter for a field within the structure S. This eliminates the need to manually write setter functions.
Example:
type State struct {
User User
Config Config
}
type Env struct {
UserService UserService
ConfigService ConfigService
}
configLens := lens.MakeLens(
func(s State) Config { return s.Config },
func(s State, c Config) State { s.Config = c; return s },
)
getConfig := readereither.Asks(func(env Env) either.Either[error, Config] {
return env.ConfigService.GetConfig()
})
result := F.Pipe2(
readereither.Of[Env, error](State{}),
readereither.ApSL(configLens, getConfig),
)
func BiMap ¶
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]
BiMap maps a pair of functions over the two type arguments of the bifunctor.
func Bind ¶
func Bind[R, E, S1, S2, T any]( setter func(T) func(S1) S2, f func(S1) ReaderEither[R, E, T], ) func(ReaderEither[R, E, S1]) ReaderEither[R, E, S2]
Bind attaches the result of a computation to a context [S1] to produce a context [S2]. This enables sequential composition where each step can depend on the results of previous steps and access the shared environment.
The setter function takes the result of the computation and returns a function that updates the context from S1 to S2.
Example:
type State struct {
User User
Config Config
}
type Env struct {
UserService UserService
ConfigService ConfigService
}
result := F.Pipe2(
readereither.Do[Env, error](State{}),
readereither.Bind(
func(user User) func(State) State {
return func(s State) State { s.User = user; return s }
},
func(s State) readereither.ReaderEither[Env, error, User] {
return readereither.Asks(func(env Env) either.Either[error, User] {
return env.UserService.GetUser()
})
},
),
readereither.Bind(
func(cfg Config) func(State) State {
return func(s State) State { s.Config = cfg; return s }
},
func(s State) readereither.ReaderEither[Env, error, Config] {
// This can access s.User from the previous step
return readereither.Asks(func(env Env) either.Either[error, Config] {
return env.ConfigService.GetConfigForUser(s.User.ID)
})
},
),
)
func BindEitherK ¶
func BindEitherK[R, E, S1, S2, T any]( setter func(T) func(S1) S2, f func(S1) Either[E, T], ) func(ReaderEither[R, E, S1]) ReaderEither[R, E, S2]
func BindL ¶
func BindL[R, E, S, T any]( lens L.Lens[S, T], f func(T) ReaderEither[R, E, T], ) func(ReaderEither[R, E, S]) ReaderEither[R, E, S]
BindL is a variant of Bind that uses a lens to focus on a specific part of the context. This provides a more ergonomic API when working with nested structures, eliminating the need to manually write setter functions.
The lens parameter provides both a getter and setter for a field of type T within the context S. The function f receives the current value of the focused field and returns a ReaderEither computation that produces an updated value.
Example:
type State struct {
User User
Config Config
}
type Env struct {
UserService UserService
ConfigService ConfigService
}
userLens := lens.MakeLens(
func(s State) User { return s.User },
func(s State, u User) State { s.User = u; return s },
)
result := F.Pipe2(
readereither.Do[Env, error](State{}),
readereither.BindL(userLens, func(user User) readereither.ReaderEither[Env, error, User] {
return readereither.Asks(func(env Env) either.Either[error, User] {
return env.UserService.GetUser()
})
}),
)
func BindReaderK ¶
func BindReaderK[R, E, S1, S2, T any]( setter func(T) func(S1) S2, f func(S1) Reader[R, T], ) func(ReaderEither[R, E, S1]) ReaderEither[R, E, S2]
func BindTo ¶
func BindTo[R, E, S1, T any]( setter func(T) S1, ) func(ReaderEither[R, E, T]) ReaderEither[R, E, S1]
BindTo initializes a new state [S1] from a value [T]
func BindToEither ¶
func BindToReader ¶
func BindToReader[ R, E, S1, T any]( setter func(T) S1, ) func(Reader[R, T]) ReaderEither[R, E, S1]
func Chain ¶
func Chain[E, L, A, B any](f func(A) ReaderEither[E, L, B]) func(ReaderEither[E, L, A]) ReaderEither[E, L, B]
func ChainEitherK ¶
func ChainEitherK[E, L, A, B any](f func(A) Either[L, B]) func(ma ReaderEither[E, L, A]) ReaderEither[E, L, B]
func ChainOptionK ¶
func ChainReaderK ¶
func Flap ¶
func Flap[L, E, B, A any](a A) func(ReaderEither[L, E, func(A) B]) ReaderEither[L, E, B]
func Fold ¶
func Fold[E, L, A, B any](onLeft func(L) Reader[E, B], onRight func(A) Reader[E, B]) func(ReaderEither[E, L, A]) Reader[E, B]
func FromPredicate ¶
func GetOrElse ¶
func GetOrElse[E, L, A any](onLeft func(L) Reader[E, A]) func(ReaderEither[E, L, A]) Reader[E, A]
func Let ¶
func Let[R, E, S1, S2, T any]( setter func(T) func(S1) S2, f func(S1) T, ) func(ReaderEither[R, E, S1]) ReaderEither[R, E, S2]
Let attaches the result of a computation to a context [S1] to produce a context [S2]
func LetL ¶
func LetL[R, E, S, T any]( lens L.Lens[S, T], f func(T) T, ) func(ReaderEither[R, E, S]) ReaderEither[R, E, S]
LetL is a variant of Let that uses a lens to focus on a specific part of the context. This provides a more ergonomic API when working with nested structures, eliminating the need to manually write setter functions.
The lens parameter provides both a getter and setter for a field of type T within the context S. The function f receives the current value of the focused field and returns a new value (without wrapping in a ReaderEither).
Example:
type State struct {
User User
Config Config
}
configLens := lens.MakeLens(
func(s State) Config { return s.Config },
func(s State, c Config) State { s.Config = c; return s },
)
result := F.Pipe2(
readereither.Do[any, error](State{Config: Config{Host: "localhost"}}),
readereither.LetL(configLens, func(cfg Config) Config {
cfg.Port = 8080
return cfg
}),
)
func LetTo ¶
func LetTo[R, E, S1, S2, T any]( setter func(T) func(S1) S2, b T, ) func(ReaderEither[R, E, S1]) ReaderEither[R, E, S2]
LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetToL ¶
func LetToL[R, E, S, T any]( lens L.Lens[S, T], b T, ) func(ReaderEither[R, E, S]) ReaderEither[R, E, S]
LetToL is a variant of LetTo that uses a lens to focus on a specific part of the context. This provides a more ergonomic API when working with nested structures, eliminating the need to manually write setter functions.
The lens parameter provides both a getter and setter for a field of type T within the context S. The value b is set directly to the focused field.
Example:
type State struct {
User User
Config Config
}
configLens := lens.MakeLens(
func(s State) Config { return s.Config },
func(s State, c Config) State { s.Config = c; return s },
)
newConfig := Config{Host: "localhost", Port: 8080}
result := F.Pipe2(
readereither.Do[any, error](State{}),
readereither.LetToL(configLens, newConfig),
)
func Local ¶
func Local[E, A, R2, R1 any](f func(R2) R1) func(ReaderEither[R1, E, A]) ReaderEither[R2, E, A]
Local changes the value of the local context during the execution of the action `ma` (similar to `Contravariant`'s `contramap`).
func MapLeft ¶
func MapLeft[C, E1, E2, A any](f func(E1) E2) func(ReaderEither[C, E1, A]) ReaderEither[C, E2, A]
MapLeft applies a mapping function to the error channel
func OrElse ¶
func OrElse[E, L1, A, L2 any](onLeft func(L1) ReaderEither[E, L2, A]) func(ReaderEither[E, L1, A]) ReaderEither[E, L2, A]
func OrLeft ¶
func OrLeft[A, L1, E, L2 any](onLeft func(L1) Reader[E, L2]) func(ReaderEither[E, L1, A]) ReaderEither[E, L2, A]
func Read ¶
func Read[E1, A, E any](e E) func(ReaderEither[E, E1, A]) Either[E1, A]
Read applies a context to a reader to obtain its value
func Traverse ¶
func Traverse[R2, R1, E, A, B any]( f Kleisli[R1, E, A, B], ) func(ReaderEither[R2, E, A]) Kleisli[R2, E, R1, B]
Traverse transforms a ReaderEither computation by applying a function that produces another ReaderEither, effectively swapping the order of environment parameters.
This function is useful when you have a computation that depends on environment R2 and produces a value of type A, and you want to transform it using a function that takes A and produces a computation depending on environment R1. The result is a curried function that takes R2 first, then R1, and produces an Either[E, B].
Type Parameters:
- R2: The outer environment type (provided first)
- R1: The inner environment type (provided second)
- E: The error type
- A: The input value type
- B: The output value type
Parameters:
- f: A Kleisli arrow that transforms A into a ReaderEither[R1, E, B]
Returns:
- A function that takes a ReaderEither[R2, E, A] and returns a Kleisli[R2, E, R1, B], which is func(R2) ReaderEither[R1, E, B]
The function preserves error handling at both levels while reordering the environment dependencies.
Example:
type Database struct {
ConnectionString string
}
type Config struct {
Timeout int
}
// Original: ReaderEither[Config, error, int] - takes Config, may fail, produces int
original := func(cfg Config) either.Either[error, int] {
if cfg.Timeout <= 0 {
return either.Left[int](errors.New("invalid timeout"))
}
return either.Right[error](cfg.Timeout * 10)
}
// Kleisli function: transforms int to ReaderEither[Database, error, string]
kleisli := func(value int) ReaderEither[Database, error, string] {
return func(db Database) either.Either[error, string] {
if S.IsEmpty(db.ConnectionString) {
return either.Left[string](errors.New("empty connection string"))
}
return either.Right[error](fmt.Sprintf("%s:%d", db.ConnectionString, value))
}
}
// Apply Traverse to get: func(ReaderEither[Config, error, int]) func(Database) ReaderEither[Config, error, string]
traversed := Traverse[Config, Database, error, int, string](kleisli)
result := traversed(original)
db := Database{ConnectionString: "localhost:5432"}
cfg := Config{Timeout: 30}
// Apply database first to get a function that takes config
configReader := result(db)
// Then apply config to get the final result
finalResult := configReader(cfg)
// finalResult is Either[error, string] = Right("localhost:5432:300")
func TraverseArray ¶
func TraverseArray[E, L, A, B any](f func(A) ReaderEither[E, L, B]) func([]A) ReaderEither[E, L, []B]
TraverseArray transforms each element of an array using a function that returns a ReaderEither, then collects the results into a single ReaderEither containing an array.
If any transformation fails, the entire operation fails with the first error encountered. All transformations are executed sequentially.
Type parameters:
- E: The context type
- L: The error type
- A: The input element type
- B: The output element type
Parameters:
- f: A function that transforms each element into a ReaderEither
Returns:
A function that takes an array and returns a ReaderEither of an array
Example:
fetchUsers := TraverseArray(func(id int) ReaderEither[Config, error, User] {
return fetchUser(id)
})
result := fetchUsers([]int{1, 2, 3})
// result(cfg) returns Right([user1, user2, user3]) or Left(error)
func TraverseArrayWithIndex ¶
func TraverseArrayWithIndex[E, L, A, B any](f func(int, A) ReaderEither[E, L, B]) func([]A) ReaderEither[E, L, []B]
TraverseArrayWithIndex is like TraverseArray but the transformation function also receives the index.
This is useful when the transformation depends on the element's position in the array.
Type parameters:
- E: The context type
- L: The error type
- A: The input element type
- B: The output element type
Parameters:
- f: A function that transforms each element and its index into a ReaderEither
Returns:
A function that takes an array and returns a ReaderEither of an array
Example:
processWithIndex := TraverseArrayWithIndex(func(i int, val string) ReaderEither[Config, error, string] {
return Of[Config, error](fmt.Sprintf("%d: %s", i, val))
})
func TraverseReader ¶
Types ¶
type Kleisli ¶
type Kleisli[R, E, A, B any] = Reader[A, ReaderEither[R, E, B]]
func Sequence ¶
func Sequence[R1, R2, E, A any](ma ReaderEither[R2, E, ReaderEither[R1, E, A]]) Kleisli[R2, E, R1, A]
Sequence swaps the order of nested environment parameters in a ReaderEither computation.
This function takes a ReaderEither that produces another ReaderEither and returns a reader.Kleisli that reverses the order of the environment parameters. The result is a curried function that takes R2 first, then R1, and produces an Either[E, A].
Type Parameters:
- R1: The first environment type (becomes inner after flip)
- R2: The second environment type (becomes outer after flip)
- E: The error type
- A: The success value type
Parameters:
- ma: A ReaderEither that takes R2 and may produce a ReaderEither[R1, E, A]
Returns:
- A reader.Kleisli[R2, R1, Either[E, A]], which is func(R2) func(R1) Either[E, A]
The function preserves error handling at both levels. Errors from the outer computation become errors in the inner Either result.
Example:
import S "github.com/IBM/fp-go/v2/string"
type Database struct {
ConnectionString string
}
type Config struct {
Timeout int
}
// Original: takes Config, may fail, produces ReaderEither[Database, error, string]
original := func(cfg Config) either.Either[error, ReaderEither[Database, error, string]] {
if cfg.Timeout <= 0 {
return either.Left[ReaderEither[Database, error, string]](errors.New("invalid timeout"))
}
return either.Right[error](func(db Database) either.Either[error, string] {
if S.IsEmpty(db.ConnectionString) {
return either.Left[string](errors.New("empty connection string"))
}
return either.Right[error](fmt.Sprintf("Query on %s with timeout %d",
db.ConnectionString, cfg.Timeout))
})
}
// Sequenced: takes Database first, then Config
sequenced := Sequence(original)
db := Database{ConnectionString: "localhost:5432"}
cfg := Config{Timeout: 30}
// Apply database first to get a function that takes config
configReader := sequenced(db)
// Then apply config to get the final result
result := configReader(cfg)
// result is Either[error, string]
func SequenceReader ¶
func SequenceReader[R1, R2, E, A any](ma ReaderEither[R2, E, Reader[R1, A]]) Kleisli[R2, E, R1, A]
SequenceReader swaps the order of environment parameters when the inner computation is a Reader.
This function is similar to Sequence but specialized for the case where the innermost computation is a pure Reader (without error handling) rather than another ReaderEither. It takes a ReaderEither that produces a Reader and returns a Reader that produces a ReaderEither.
Type Parameters:
- R1: The first environment type (becomes outer after flip)
- R2: The second environment type (becomes inner after flip)
- E: The error type (only present in the ReaderEither layer)
- A: The success value type
Parameters:
- ma: A ReaderEither that takes R2 and may produce a Reader[R1, A]
Returns:
- A reader.Kleisli[R2, R1, Either[E, A]], which is func(R2) func(R1) Either[E, A]
The function preserves error handling from the outer ReaderEither layer. If the outer computation fails, the error is propagated to the inner ReaderEither result.
Example:
type Database struct {
ConnectionString string
}
type Config struct {
Timeout int
}
// Original: takes Config, may fail, produces Reader[Database, string]
original := func(cfg Config) either.Either[error, Reader[Database, string]] {
if cfg.Timeout <= 0 {
return either.Left[Reader[Database, string]](errors.New("invalid timeout"))
}
return either.Right[error](func(db Database) string {
return fmt.Sprintf("Query on %s with timeout %d",
db.ConnectionString, cfg.Timeout)
})
}
// Sequenced: takes Database first, then Config
sequenced := SequenceReader(original)
db := Database{ConnectionString: "localhost:5432"}
cfg := Config{Timeout: 30}
// Apply database first to get a function that takes config
configReader := sequenced(db)
// Then apply config to get the final result
result := configReader(cfg)
// result is Either[error, string]
func TailRec ¶
func TailRec[R, E, A, B any](f Kleisli[R, E, A, tailrec.Trampoline[A, B]]) Kleisli[R, E, A, B]
type Operator ¶
type Operator[R, E, A, B any] = Kleisli[R, E, ReaderEither[R, E, A], B]
type ReaderEither ¶
func Do ¶
func Do[R, E, S any]( empty S, ) ReaderEither[R, E, S]
Do creates an empty context of type [S] to be used with the Bind operation. This is the starting point for do-notation style composition.
Example:
type State struct {
User User
Config Config
}
type Env struct {
UserService UserService
ConfigService ConfigService
}
result := readereither.Do[Env, error](State{})
func Flatten ¶
func Flatten[E, L, A any](mma ReaderEither[E, L, ReaderEither[E, L, A]]) ReaderEither[E, L, A]
func FromEither ¶
func FromEither[E, L, A any](e Either[L, A]) ReaderEither[E, L, A]
func FromReader ¶
func FromReader[L, E, A any](r Reader[E, A]) ReaderEither[E, L, A]
func LeftReader ¶
func LeftReader[A, E, L any](l Reader[E, L]) ReaderEither[E, L, A]
func MonadAp ¶
func MonadAp[B, E, L, A any](fab ReaderEither[E, L, func(A) B], fa ReaderEither[E, L, A]) ReaderEither[E, L, B]
func MonadBiMap ¶
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]
func MonadChain ¶
func MonadChain[E, L, A, B any](ma ReaderEither[E, L, A], f func(A) ReaderEither[E, L, B]) ReaderEither[E, L, B]
func MonadChainEitherK ¶
func MonadChainEitherK[E, L, A, B any](ma ReaderEither[E, L, A], f func(A) Either[L, B]) ReaderEither[E, L, B]
func MonadChainReaderK ¶
func MonadFlap ¶
func MonadFlap[L, E, A, B any](fab ReaderEither[L, E, func(A) B], a A) ReaderEither[L, E, B]
func MonadMap ¶
func MonadMap[E, L, A, B any](fa ReaderEither[E, L, A], f func(A) B) ReaderEither[E, L, B]
func MonadMapLeft ¶
func MonadMapLeft[C, E1, E2, A any](fa ReaderEither[C, E1, A], f func(E1) E2) ReaderEither[C, E2, A]
func RightReader ¶
func RightReader[L, E, A any](r Reader[E, A]) ReaderEither[E, L, A]
func SequenceArray ¶
func SequenceArray[E, L, A any](ma []ReaderEither[E, L, A]) ReaderEither[E, L, []A]
SequenceArray converts an array of ReaderEither into a ReaderEither of an array.
This is useful when you have multiple independent computations and want to execute them all and collect their results. If any computation fails, the entire operation fails with the first error.
Type parameters:
- E: The context type
- L: The error type
- A: The element type
Parameters:
- ma: An array of ReaderEither computations
Returns:
A ReaderEither that produces an array of results
Example:
computations := []ReaderEither[Config, error, int]{
fetchCount("users"),
fetchCount("posts"),
fetchCount("comments"),
}
result := SequenceArray(computations)
// result(cfg) returns Right([userCount, postCount, commentCount]) or Left(error)