Documentation
¶
Overview ¶
Package readerioeither provides a functional programming abstraction that combines three powerful concepts: Reader, IO, and Either monads.
Fantasy Land Specification ¶
This is a monad transformer combining:
- Reader monad: https://github.com/fantasyland/fantasy-land
- IO monad: https://github.com/fantasyland/fantasy-land
- Either monad: https://github.com/fantasyland/fantasy-land#either
Implemented Fantasy Land algebras:
- Functor: https://github.com/fantasyland/fantasy-land#functor
- Bifunctor: https://github.com/fantasyland/fantasy-land#bifunctor
- Apply: https://github.com/fantasyland/fantasy-land#apply
- Applicative: https://github.com/fantasyland/fantasy-land#applicative
- Chain: https://github.com/fantasyland/fantasy-land#chain
- Monad: https://github.com/fantasyland/fantasy-land#monad
- Alt: https://github.com/fantasyland/fantasy-land#alt
ReaderIOEither ¶
ReaderIOEither[R, E, A] represents a computation that:
- Depends on some context/environment of type R (Reader)
- Performs side effects (IO)
- Can fail with an error of type E or succeed with a value of type A (Either)
This is particularly useful for:
- Dependency injection patterns
- Error handling in effectful computations
- Composing operations that need access to shared configuration or context
Core Operations ¶
Construction:
- Of/Right: Create a successful computation
- Left/ThrowError: Create a failed computation
- FromEither: Lift an Either into ReaderIOEither
- FromIO: Lift an IO into ReaderIOEither
- FromReader: Lift a Reader into ReaderIOEither
- FromIOEither: Lift an IOEither into ReaderIOEither
- TryCatch: Wrap error-returning functions
Transformation:
- Map: Transform the success value
- MapLeft: Transform the error value
- BiMap: Transform both success and error values
- Chain/Bind: Sequence dependent computations
- Flatten: Flatten nested ReaderIOEither
Combination:
- Ap: Apply a function in a context to a value in a context
- SequenceArray: Convert array of ReaderIOEither to ReaderIOEither of array
- TraverseArray: Map and sequence in one operation
Error Handling:
- Fold: Handle both success and error cases
- GetOrElse: Provide a default value on error
- OrElse: Try an alternative computation on error
- Alt: Choose the first successful computation
Context Access:
- Ask: Get the current context
- Asks: Get a value derived from the context
- Local: Run a computation with a modified context
Resource Management:
- Bracket: Ensure resource cleanup
- WithResource: Manage resource lifecycle
Example Usage ¶
type Config struct {
BaseURL string
Timeout time.Duration
}
// A computation that depends on Config, performs IO, and can fail
func fetchUser(id int) readerioeither.ReaderIOEither[Config, error, User] {
return func(cfg Config) ioeither.IOEither[error, User] {
return func() either.Either[error, User] {
// Use cfg.BaseURL and cfg.Timeout to fetch user
// Return either.Right(user) or either.Left(err)
}
}
}
// Compose operations
result := function.Pipe2(
fetchUser(123),
readerioeither.Map[Config, error](func(u User) string { return u.Name }),
readerioeither.Chain[Config, error](func(name string) readerioeither.ReaderIOEither[Config, error, string] {
return readerioeither.Of[Config, error]("Hello, " + name)
}),
)
// Execute with config
config := Config{BaseURL: "https://api.example.com", Timeout: 30 * time.Second}
outcome := result(config)() // Returns either.Either[error, string]
Copyright (c) 2025 IBM Corp. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
Index ¶
- func Ap[B, R, E, A any](fa ReaderIOEither[R, E, A]) func(fab ReaderIOEither[R, E, func(A) B]) ReaderIOEither[R, E, B]
- 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]
- func ChainFirstReaderOptionK[R, A, B, E any](onNone func() E) func(readeroption.Kleisli[R, A, B]) Operator[R, E, A, A]
- func ChainLeft[R, EA, EB, A any](f Kleisli[R, EB, EA, A]) func(ReaderIOEither[R, EA, A]) ReaderIOEither[R, EB, A]
- func ChainOptionK[R, A, B, E any](onNone func() E) func(func(A) Option[B]) Operator[R, E, A, B]
- func ChainReaderOptionK[R, A, B, E any](onNone func() E) func(readeroption.Kleisli[R, A, B]) Operator[R, E, A, B]
- func Eitherize0[F ~func(C) (R, error), C, R any](f F) func() ReaderIOEither[C, error, R]
- func Eitherize1[F ~func(C, T0) (R, error), T0, C, R any](f F) func(T0) ReaderIOEither[C, error, R]
- func Eitherize10[F ~func(C, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error), ...](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) ReaderIOEither[C, error, R]
- func Eitherize2[F ~func(C, T0, T1) (R, error), T0, T1, C, R any](f F) func(T0, T1) ReaderIOEither[C, error, R]
- func Eitherize3[F ~func(C, T0, T1, T2) (R, error), T0, T1, T2, C, R any](f F) func(T0, T1, T2) ReaderIOEither[C, error, R]
- func Eitherize4[F ~func(C, T0, T1, T2, T3) (R, error), T0, T1, T2, T3, C, R any](f F) func(T0, T1, T2, T3) ReaderIOEither[C, error, R]
- func Eitherize5[F ~func(C, T0, T1, T2, T3, T4) (R, error), T0, T1, T2, T3, T4, C, R any](f F) func(T0, T1, T2, T3, T4) ReaderIOEither[C, error, R]
- func Eitherize6[F ~func(C, T0, T1, T2, T3, T4, T5) (R, error), ...](f F) func(T0, T1, T2, T3, T4, T5) ReaderIOEither[C, error, R]
- func Eitherize7[F ~func(C, T0, T1, T2, T3, T4, T5, T6) (R, error), ...](f F) func(T0, T1, T2, T3, T4, T5, T6) ReaderIOEither[C, error, R]
- func Eitherize8[F ~func(C, T0, T1, T2, T3, T4, T5, T6, T7) (R, error), ...](f F) func(T0, T1, T2, T3, T4, T5, T6, T7) ReaderIOEither[C, error, R]
- func Eitherize9[F ~func(C, T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error), ...](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8) ReaderIOEither[C, error, R]
- func Eq[R, E, A any](eq EQ.Eq[either.Either[E, A]]) func(R) EQ.Eq[ReaderIOEither[R, E, A]]
- func Flap[R, E, B, A any](a A) func(ReaderIOEither[R, E, func(A) B]) ReaderIOEither[R, E, B]
- func Fold[R, E, A, B any](onLeft func(E) ReaderIO[R, B], onRight func(A) ReaderIO[R, B]) func(ReaderIOEither[R, E, A]) ReaderIO[R, B]
- func From0[F ~func(C) func() (R, error), C, R any](f F) func() ReaderIOEither[C, error, R]
- func From1[F ~func(C, T0) func() (R, error), T0, C, R any](f F) func(T0) ReaderIOEither[C, error, R]
- func From10[F ~func(C, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) func() (R, error), ...](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) ReaderIOEither[C, error, R]
- func From2[F ~func(C, T0, T1) func() (R, error), T0, T1, C, R any](f F) func(T0, T1) ReaderIOEither[C, error, R]
- func From3[F ~func(C, T0, T1, T2) func() (R, error), T0, T1, T2, C, R any](f F) func(T0, T1, T2) ReaderIOEither[C, error, R]
- func From4[F ~func(C, T0, T1, T2, T3) func() (R, error), T0, T1, T2, T3, C, R any](f F) func(T0, T1, T2, T3) ReaderIOEither[C, error, R]
- func From5[F ~func(C, T0, T1, T2, T3, T4) func() (R, error), T0, T1, T2, T3, T4, C, R any](f F) func(T0, T1, T2, T3, T4) ReaderIOEither[C, error, R]
- func From6[F ~func(C, T0, T1, T2, T3, T4, T5) func() (R, error), ...](f F) func(T0, T1, T2, T3, T4, T5) ReaderIOEither[C, error, R]
- func From7[F ~func(C, T0, T1, T2, T3, T4, T5, T6) func() (R, error), ...](f F) func(T0, T1, T2, T3, T4, T5, T6) ReaderIOEither[C, error, R]
- func From8[F ~func(C, T0, T1, T2, T3, T4, T5, T6, T7) func() (R, error), ...](f F) func(T0, T1, T2, T3, T4, T5, T6, T7) ReaderIOEither[C, error, R]
- func From9[F ~func(C, T0, T1, T2, T3, T4, T5, T6, T7, T8) func() (R, error), ...](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8) ReaderIOEither[C, error, R]
- func FromOption[R, A, E any](onNone func() E) func(Option[A]) ReaderIOEither[R, E, A]
- func FromPredicate[R, E, A any](pred func(A) bool, onFalse func(A) E) func(A) ReaderIOEither[R, E, A]
- func FromStrictEquals[R any, E, A comparable]() func(R) EQ.Eq[ReaderIOEither[R, E, A]]
- func Functor[R, E, A, B any]() functor.Functor[A, B, ReaderIOEither[R, E, A], ReaderIOEither[R, E, B]]
- func GetOrElse[R, E, A any](onLeft func(E) ReaderIO[R, A]) func(ReaderIOEither[R, E, A]) ReaderIO[R, A]
- func Local[E, A, R1, R2 any](f func(R2) R1) func(ReaderIOEither[R1, E, A]) ReaderIOEither[R2, E, A]
- func MapLeft[R, A, E1, E2 any](f func(E1) E2) func(ReaderIOEither[R, E1, A]) ReaderIOEither[R, E2, A]
- func Monad[R, E, A, B any]() ...
- func OrElse[R, E1, A, E2 any](onLeft func(E1) ReaderIOEither[R, E2, A]) func(ReaderIOEither[R, E1, A]) ReaderIOEither[R, E2, A]
- func OrLeft[A, E1, R, E2 any](onLeft func(E1) ReaderIO[R, E2]) func(ReaderIOEither[R, E1, A]) ReaderIOEither[R, E2, A]
- func Pointed[R, E, A any]() pointed.Pointed[A, ReaderIOEither[R, E, A]]
- func Read[E, A, R any](r R) func(ReaderIOEither[R, E, A]) IOEither[E, A]
- func TapReaderOptionK[R, A, B, E any](onNone func() E) func(readeroption.Kleisli[R, A, B]) Operator[R, E, A, A]
- func Traverse[R2, R1, E, A, B any](f Kleisli[R1, E, A, B]) func(ReaderIOEither[R2, E, A]) Kleisli[R2, E, R1, B]
- func TraverseArrayWithIndex[R, E, A, B any](f func(int, A) ReaderIOEither[R, E, B]) func([]A) ReaderIOEither[R, E, []B]
- func TraverseReader[R2, R1, E, A, B any](f reader.Kleisli[R1, A, B]) func(ReaderIOEither[R2, E, A]) Kleisli[R2, E, R1, B]
- func TraverseRecord[K comparable, R, E, A, B any](f func(A) ReaderIOEither[R, E, B]) func(map[K]A) ReaderIOEither[R, E, map[K]B]
- func TraverseRecordWithIndex[K comparable, R, E, A, B any](f func(K, A) ReaderIOEither[R, E, B]) func(map[K]A) ReaderIOEither[R, E, map[K]B]
- func Uneitherize0[F ~func() ReaderIOEither[C, error, R], C, R any](f F) func(C) (R, error)
- func Uneitherize1[F ~func(T0) ReaderIOEither[C, error, R], T0, C, R any](f F) func(C, T0) (R, error)
- func Uneitherize10[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) ReaderIOEither[C, error, R], ...](f F) func(C, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error)
- func Uneitherize2[F ~func(T0, T1) ReaderIOEither[C, error, R], T0, T1, C, R any](f F) func(C, T0, T1) (R, error)
- func Uneitherize3[F ~func(T0, T1, T2) ReaderIOEither[C, error, R], T0, T1, T2, C, R any](f F) func(C, T0, T1, T2) (R, error)
- func Uneitherize4[F ~func(T0, T1, T2, T3) ReaderIOEither[C, error, R], T0, T1, T2, T3, C, R any](f F) func(C, T0, T1, T2, T3) (R, error)
- func Uneitherize5[F ~func(T0, T1, T2, T3, T4) ReaderIOEither[C, error, R], ...](f F) func(C, T0, T1, T2, T3, T4) (R, error)
- func Uneitherize6[F ~func(T0, T1, T2, T3, T4, T5) ReaderIOEither[C, error, R], ...](f F) func(C, T0, T1, T2, T3, T4, T5) (R, error)
- func Uneitherize7[F ~func(T0, T1, T2, T3, T4, T5, T6) ReaderIOEither[C, error, R], ...](f F) func(C, T0, T1, T2, T3, T4, T5, T6) (R, error)
- func Uneitherize8[F ~func(T0, T1, T2, T3, T4, T5, T6, T7) ReaderIOEither[C, error, R], ...](f F) func(C, T0, T1, T2, T3, T4, T5, T6, T7) (R, error)
- func Uneitherize9[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8) ReaderIOEither[C, error, R], ...](f F) func(C, T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error)
- type Consumer
- type Either
- type IO
- type IOEither
- type Kleisli
- func FromReaderOption[R, A, E any](onNone func() E) Kleisli[R, E, ReaderOption[R, A], A]
- func ReduceArray[R, E, A, B any](reduce func(B, A) B, initial B) Kleisli[R, E, []ReaderIOEither[R, E, A], B]
- func ReduceArrayM[R, E, A any](m monoid.Monoid[A]) Kleisli[R, E, []ReaderIOEither[R, E, A], A]
- func Sequence[R1, R2, E, A any](ma ReaderIOEither[R2, E, ReaderIOEither[R1, E, A]]) Kleisli[R2, E, R1, A]
- func SequenceReader[R1, R2, E, A any](ma ReaderIOEither[R2, E, Reader[R1, A]]) Kleisli[R2, E, R1, A]
- func SequenceReaderEither[R1, R2, E, A any](ma ReaderIOEither[R2, E, ReaderEither[R1, E, A]]) Kleisli[R2, E, R1, A]
- func SequenceReaderIO[R1, R2, E, A any](ma ReaderIOEither[R2, E, ReaderIO[R1, A]]) Kleisli[R2, E, R1, A]
- func TailRec[R, E, A, B any](f Kleisli[R, E, A, tailrec.Trampoline[A, B]]) Kleisli[R, E, A, B]
- func TraverseArray[R, E, A, B any](f Kleisli[R, E, A, B]) Kleisli[R, E, []A, []B]
- func TraverseReduceArray[R, E, A, B, C any](trfrm Kleisli[R, E, A, B], reduce func(C, B) C, initial C) Kleisli[R, E, []A, C]
- func TraverseReduceArrayM[R, E, A, B any](trfrm Kleisli[R, E, A, B], m monoid.Monoid[B]) Kleisli[R, E, []A, B]
- func WithResource[A, L, E, R, ANY any](onCreate ReaderIOEither[L, E, R], onRelease Kleisli[L, E, R, ANY]) Kleisli[L, E, Kleisli[L, E, R, A], A]
- type Monoid
- func AltMonoid[R, E, A any](zero lazy.Lazy[ReaderIOEither[R, E, A]]) Monoid[R, E, A]
- func AlternativeMonoid[R, E, A any](m monoid.Monoid[A]) Monoid[R, E, A]
- func ApplicativeMonoid[R, E, A any](m monoid.Monoid[A]) Monoid[R, E, A]
- func ApplicativeMonoidPar[R, E, A any](m monoid.Monoid[A]) Monoid[R, E, A]
- func ApplicativeMonoidSeq[R, E, A any](m monoid.Monoid[A]) Monoid[R, E, A]
- type Operator
- func After[R, E, A any](timestamp time.Time) Operator[R, E, A, A]
- func Alt[R, E, A any](second L.Lazy[ReaderIOEither[R, E, A]]) Operator[R, E, A, A]
- func ApEitherS[R, E, S1, S2, T any](setter func(T) func(S1) S2, fa Either[E, T]) Operator[R, E, S1, S2]
- func ApEitherSL[R, E, S, T any](lens L.Lens[S, T], fa Either[E, T]) Operator[R, E, S, S]
- func ApIOEitherS[R, E, S1, S2, T any](setter func(T) func(S1) S2, fa IOEither[E, T]) Operator[R, E, S1, S2]
- func ApIOEitherSL[R, E, S, T any](lens L.Lens[S, T], fa IOEither[E, T]) Operator[R, E, S, S]
- func ApIOS[R, E, S1, S2, T any](setter func(T) func(S1) S2, fa IO[T]) Operator[R, E, S1, S2]
- func ApIOSL[R, E, S, T any](lens L.Lens[S, T], fa IO[T]) Operator[R, E, S, S]
- func ApReaderIOS[R, E, S1, S2, T any](setter func(T) func(S1) S2, fa ReaderIO[R, T]) Operator[R, E, S1, S2]
- func ApReaderIOSL[R, E, S, T any](lens L.Lens[S, T], fa ReaderIO[R, T]) Operator[R, E, S, S]
- func ApReaderS[R, E, S1, S2, T any](setter func(T) func(S1) S2, fa Reader[R, T]) Operator[R, E, S1, S2]
- func ApReaderSL[R, E, S, T any](lens L.Lens[S, T], fa Reader[R, T]) Operator[R, E, S, S]
- func ApS[R, E, S1, S2, T any](setter func(T) func(S1) S2, fa ReaderIOEither[R, E, T]) Operator[R, E, S1, S2]
- func ApSL[R, E, S, T any](lens L.Lens[S, T], fa ReaderIOEither[R, E, T]) Operator[R, E, S, S]
- func Bind[R, E, S1, S2, T any](setter func(T) func(S1) S2, f func(S1) ReaderIOEither[R, E, T]) Operator[R, E, S1, S2]
- func BindEitherK[R, E, S1, S2, T any](setter func(T) func(S1) S2, f either.Kleisli[E, S1, T]) Operator[R, E, S1, S2]
- func BindIOEitherK[R, E, S1, S2, T any](setter func(T) func(S1) S2, f ioeither.Kleisli[E, S1, T]) Operator[R, E, S1, S2]
- func BindIOEitherKL[R, E, S, T any](lens L.Lens[S, T], f ioeither.Kleisli[E, T, T]) Operator[R, E, S, S]
- func BindIOK[R, E, S1, S2, T any](setter func(T) func(S1) S2, f io.Kleisli[S1, T]) Operator[R, E, S1, S2]
- func BindIOKL[R, E, S, T any](lens L.Lens[S, T], f io.Kleisli[T, T]) Operator[R, E, S, S]
- func BindL[R, E, S, T any](lens L.Lens[S, T], f func(T) ReaderIOEither[R, E, T]) Operator[R, E, S, S]
- func BindReaderIOK[E, R, S1, S2, T any](setter func(T) func(S1) S2, f readerio.Kleisli[R, S1, T]) Operator[R, E, S1, S2]
- func BindReaderIOKL[E, R, S, T any](lens L.Lens[S, T], f readerio.Kleisli[R, T, T]) Operator[R, E, S, S]
- func BindReaderK[E, R, S1, S2, T any](setter func(T) func(S1) S2, f reader.Kleisli[R, S1, T]) Operator[R, E, S1, S2]
- func BindReaderKL[E, R, S, T any](lens L.Lens[S, T], f reader.Kleisli[R, T, T]) Operator[R, E, S, S]
- func BindTo[R, E, S1, T any](setter func(T) S1) Operator[R, E, T, S1]
- func Chain[R, E, A, B any](f Kleisli[R, E, A, B]) Operator[R, E, A, B]
- func ChainConsumer[R, E, A any](c Consumer[A]) Operator[R, E, A, struct{}]
- func ChainEitherK[R, E, A, B any](f either.Kleisli[E, A, B]) Operator[R, E, A, B]
- func ChainFirst[R, E, A, B any](f Kleisli[R, E, A, B]) Operator[R, E, A, A]
- func ChainFirstConsumer[R, E, A any](c Consumer[A]) Operator[R, E, A, A]
- func ChainFirstEitherK[R, E, A, B any](f either.Kleisli[E, A, B]) Operator[R, E, A, A]
- func ChainFirstIOK[R, E, A, B any](f io.Kleisli[A, B]) Operator[R, E, A, A]
- func ChainFirstLeft[A, R, EA, EB, B any](f Kleisli[R, EB, EA, B]) Operator[R, EA, A, A]
- func ChainFirstReaderEitherK[E, R, A, B any](f RE.Kleisli[R, E, A, B]) Operator[R, E, A, A]
- func ChainFirstReaderIOK[E, R, A, B any](f readerio.Kleisli[R, A, B]) Operator[R, E, A, A]
- func ChainFirstReaderK[E, R, A, B any](f reader.Kleisli[R, A, B]) Operator[R, E, A, A]
- func ChainIOEitherK[R, E, A, B any](f IOE.Kleisli[E, A, B]) Operator[R, E, A, B]
- func ChainIOK[R, E, A, B any](f io.Kleisli[A, B]) Operator[R, E, A, B]
- func ChainReaderEitherK[E, R, A, B any](f RE.Kleisli[R, E, A, B]) Operator[R, E, A, B]
- func ChainReaderIOK[E, R, A, B any](f readerio.Kleisli[R, A, B]) Operator[R, E, A, B]
- func ChainReaderK[E, R, A, B any](f reader.Kleisli[R, A, B]) Operator[R, E, A, B]
- func Delay[R, E, A any](delay time.Duration) Operator[R, E, A, A]
- func Let[R, E, S1, S2, T any](setter func(T) func(S1) S2, f func(S1) T) Operator[R, E, S1, S2]
- func LetL[R, E, S, T any](lens L.Lens[S, T], f func(T) T) Operator[R, E, S, S]
- func LetTo[R, E, S1, S2, T any](setter func(T) func(S1) S2, b T) Operator[R, E, S1, S2]
- func LetToL[R, E, S, T any](lens L.Lens[S, T], b T) Operator[R, E, S, S]
- func Map[R, E, A, B any](f func(A) B) Operator[R, E, A, B]
- func MapTo[R, E, A, B any](b B) Operator[R, E, A, B]
- func Tap[R, E, A, B any](f Kleisli[R, E, A, B]) Operator[R, E, A, A]
- func TapEitherK[R, E, A, B any](f either.Kleisli[E, A, B]) Operator[R, E, A, A]
- func TapIOK[R, E, A, B any](f io.Kleisli[A, B]) Operator[R, E, A, A]
- func TapLeft[A, R, EA, EB, B any](f Kleisli[R, EB, EA, B]) Operator[R, EA, A, A]
- func TapReaderEitherK[E, R, A, B any](f RE.Kleisli[R, E, A, B]) Operator[R, E, A, A]
- func TapReaderIOK[E, R, A, B any](f readerio.Kleisli[R, A, B]) Operator[R, E, A, A]
- func TapReaderK[E, R, A, B any](f reader.Kleisli[R, A, B]) Operator[R, E, A, A]
- func WithLock[R, E, A any](lock func() context.CancelFunc) Operator[R, E, A, A]
- type Option
- type Reader
- type ReaderEither
- type ReaderIO
- type ReaderIOEither
- func Ask[R, E any]() ReaderIOEither[R, E, R]
- func Asks[E, R, A any](r Reader[R, A]) ReaderIOEither[R, E, A]
- func Bracket[R, E, A, B, ANY any](acquire ReaderIOEither[R, E, A], use func(A) ReaderIOEither[R, E, B], ...) ReaderIOEither[R, E, B]
- func Defer[R, E, A any](gen L.Lazy[ReaderIOEither[R, E, A]]) ReaderIOEither[R, E, A]
- func Do[R, E, S any](empty S) ReaderIOEither[R, E, S]
- func Flatten[R, E, A any](mma ReaderIOEither[R, E, ReaderIOEither[R, E, A]]) ReaderIOEither[R, E, A]
- func FromEither[R, E, A any](t either.Either[E, A]) ReaderIOEither[R, E, A]
- func FromIO[R, E, A any](ma IO[A]) ReaderIOEither[R, E, A]
- func FromIOEither[R, E, A any](ma IOEither[E, A]) ReaderIOEither[R, E, A]
- func FromReader[E, R, A any](ma Reader[R, A]) ReaderIOEither[R, E, A]
- func FromReaderEither[R, E, A any](ma RE.ReaderEither[R, E, A]) ReaderIOEither[R, E, A]
- func FromReaderIO[E, R, A any](ma ReaderIO[R, A]) ReaderIOEither[R, E, A]
- func Left[R, A, E any](e E) ReaderIOEither[R, E, A]
- func LeftIO[R, A, E any](ma IO[E]) ReaderIOEither[R, E, A]
- func LeftReader[A, R, E any](ma Reader[R, E]) ReaderIOEither[R, E, A]
- func LeftReaderIO[A, R, E any](me ReaderIO[R, E]) ReaderIOEither[R, E, A]
- func Memoize[R, E, A any](rdr ReaderIOEither[R, E, A]) ReaderIOEither[R, E, A]
- func MonadAlt[R, E, A any](first ReaderIOEither[R, E, A], second L.Lazy[ReaderIOEither[R, E, A]]) ReaderIOEither[R, E, A]
- func MonadAp[R, E, A, B any](fab ReaderIOEither[R, E, func(A) B], fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]
- func MonadApPar[R, E, A, B any](fab ReaderIOEither[R, E, func(A) B], fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]
- func MonadApSeq[R, E, A, B any](fab ReaderIOEither[R, E, func(A) B], fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]
- 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]
- func MonadChain[R, E, A, B any](fa ReaderIOEither[R, E, A], f Kleisli[R, E, A, B]) ReaderIOEither[R, E, B]
- func MonadChainEitherK[R, E, A, B any](ma ReaderIOEither[R, E, A], f either.Kleisli[E, A, B]) ReaderIOEither[R, E, B]
- func MonadChainFirst[R, E, A, B any](fa ReaderIOEither[R, E, A], f Kleisli[R, E, A, B]) ReaderIOEither[R, E, A]
- func MonadChainFirstEitherK[R, E, A, B any](ma ReaderIOEither[R, E, A], f either.Kleisli[E, A, B]) ReaderIOEither[R, E, A]
- func MonadChainFirstIOK[R, E, A, B any](ma ReaderIOEither[R, E, A], f io.Kleisli[A, B]) ReaderIOEither[R, E, A]
- func MonadChainFirstLeft[A, R, EA, EB, B any](ma ReaderIOEither[R, EA, A], f Kleisli[R, EB, EA, B]) ReaderIOEither[R, EA, A]
- func MonadChainFirstReaderEitherK[R, E, A, B any](ma ReaderIOEither[R, E, A], f RE.Kleisli[R, E, A, B]) ReaderIOEither[R, E, A]
- func MonadChainFirstReaderIOK[E, R, A, B any](ma ReaderIOEither[R, E, A], f readerio.Kleisli[R, A, B]) ReaderIOEither[R, E, A]
- func MonadChainFirstReaderK[E, R, A, B any](ma ReaderIOEither[R, E, A], f reader.Kleisli[R, A, B]) ReaderIOEither[R, E, A]
- func MonadChainIOEitherK[R, E, A, B any](ma ReaderIOEither[R, E, A], f IOE.Kleisli[E, A, B]) ReaderIOEither[R, E, B]
- func MonadChainIOK[R, E, A, B any](ma ReaderIOEither[R, E, A], f io.Kleisli[A, B]) ReaderIOEither[R, E, B]
- func MonadChainLeft[R, EA, EB, A any](fa ReaderIOEither[R, EA, A], f Kleisli[R, EB, EA, A]) ReaderIOEither[R, EB, A]
- func MonadChainReaderEitherK[R, E, A, B any](ma ReaderIOEither[R, E, A], f RE.Kleisli[R, E, A, B]) ReaderIOEither[R, E, B]
- func MonadChainReaderIOK[E, R, A, B any](ma ReaderIOEither[R, E, A], f readerio.Kleisli[R, A, B]) ReaderIOEither[R, E, B]
- func MonadChainReaderK[E, R, A, B any](ma ReaderIOEither[R, E, A], f reader.Kleisli[R, A, B]) ReaderIOEither[R, E, B]
- func MonadFlap[R, E, B, A any](fab ReaderIOEither[R, E, func(A) B], a A) ReaderIOEither[R, E, B]
- func MonadMap[R, E, A, B any](fa ReaderIOEither[R, E, A], f func(A) B) ReaderIOEither[R, E, B]
- func MonadMapLeft[R, E1, E2, A any](fa ReaderIOEither[R, E1, A], f func(E1) E2) ReaderIOEither[R, E2, A]
- func MonadMapTo[R, E, A, B any](fa ReaderIOEither[R, E, A], b B) ReaderIOEither[R, E, B]
- func MonadReduceArray[R, E, A, B any](as []ReaderIOEither[R, E, A], reduce func(B, A) B, initial B) ReaderIOEither[R, E, B]
- func MonadReduceArrayM[R, E, A any](as []ReaderIOEither[R, E, A], m monoid.Monoid[A]) ReaderIOEither[R, E, A]
- func MonadTap[R, E, A, B any](fa ReaderIOEither[R, E, A], f Kleisli[R, E, A, B]) ReaderIOEither[R, E, A]
- func MonadTapEitherK[R, E, A, B any](ma ReaderIOEither[R, E, A], f either.Kleisli[E, A, B]) ReaderIOEither[R, E, A]
- func MonadTapIOK[R, E, A, B any](ma ReaderIOEither[R, E, A], f io.Kleisli[A, B]) ReaderIOEither[R, E, A]
- func MonadTapLeft[A, R, EA, EB, B any](ma ReaderIOEither[R, EA, A], f Kleisli[R, EB, EA, B]) ReaderIOEither[R, EA, A]
- func MonadTapReaderEitherK[R, E, A, B any](ma ReaderIOEither[R, E, A], f RE.Kleisli[R, E, A, B]) ReaderIOEither[R, E, A]
- func MonadTapReaderIOK[E, R, A, B any](ma ReaderIOEither[R, E, A], f readerio.Kleisli[R, A, B]) ReaderIOEither[R, E, A]
- func MonadTapReaderK[E, R, A, B any](ma ReaderIOEither[R, E, A], f reader.Kleisli[R, A, B]) ReaderIOEither[R, E, A]
- func MonadTraverseReduceArray[R, E, A, B, C any](as []A, trfrm Kleisli[R, E, A, B], reduce func(C, B) C, initial C) ReaderIOEither[R, E, C]
- func MonadTraverseReduceArrayM[R, E, A, B any](as []A, trfrm Kleisli[R, E, A, B], m monoid.Monoid[B]) ReaderIOEither[R, E, B]
- func Of[R, E, A any](a A) ReaderIOEither[R, E, A]
- func Retrying[R, E, A any](policy retry.RetryPolicy, action Kleisli[R, E, retry.RetryStatus, A], ...) ReaderIOEither[R, E, A]
- func Right[R, E, A any](a A) ReaderIOEither[R, E, A]
- func RightIO[R, E, A any](ma IO[A]) ReaderIOEither[R, E, A]
- func RightReader[E, R, A any](ma Reader[R, A]) ReaderIOEither[R, E, A]
- func RightReaderIO[E, R, A any](ma ReaderIO[R, A]) ReaderIOEither[R, E, A]
- func SequenceArray[R, E, A any](ma []ReaderIOEither[R, E, A]) ReaderIOEither[R, E, []A]
- func SequenceRecord[K comparable, R, E, A any](ma map[K]ReaderIOEither[R, E, A]) ReaderIOEither[R, E, map[K]A]
- func SequenceT1[R, E, A any](a ReaderIOEither[R, E, A]) ReaderIOEither[R, E, T.Tuple1[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]]
- func SequenceT3[R, E, A, B, C any](a ReaderIOEither[R, E, A], b ReaderIOEither[R, E, B], ...) ReaderIOEither[R, E, T.Tuple3[A, B, C]]
- func SequenceT4[R, E, A, B, C, D any](a ReaderIOEither[R, E, A], b ReaderIOEither[R, E, B], ...) ReaderIOEither[R, E, T.Tuple4[A, B, C, D]]
- func Swap[R, E, A any](val ReaderIOEither[R, E, A]) ReaderIOEither[R, A, E]
- func ThrowError[R, A, E any](e E) ReaderIOEither[R, E, A]
- func TryCatch[R, E, A any](f func(R) func() (A, error), onThrow func(error) E) ReaderIOEither[R, E, A]
- type ReaderOption
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Ap ¶
func Ap[B, R, E, A any](fa ReaderIOEither[R, E, A]) func(fab ReaderIOEither[R, E, func(A) B]) ReaderIOEither[R, E, B]
Ap returns a function that applies a function in a context to a value in a context. This is the curried version of MonadAp.
func BiMap ¶
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]
BiMap returns a function that maps over both the error and success channels. This is the curried version of MonadBiMap.
func ChainFirstReaderOptionK ¶
func ChainFirstReaderOptionK[R, A, B, E any](onNone func() E) func(readeroption.Kleisli[R, A, B]) Operator[R, E, A, A]
func ChainLeft ¶
func ChainLeft[R, EA, EB, A any](f Kleisli[R, EB, EA, A]) func(ReaderIOEither[R, EA, A]) ReaderIOEither[R, EB, A]
func ChainOptionK ¶
func ChainOptionK[R, A, B, E any](onNone func() E) func(func(A) Option[B]) Operator[R, E, A, B]
ChainOptionK returns a function that chains an Option-returning function into ReaderIOEither. If the Option is None, the provided error function is called to produce the error value.
func ChainReaderOptionK ¶
func ChainReaderOptionK[R, A, B, E any](onNone func() E) func(readeroption.Kleisli[R, A, B]) Operator[R, E, A, B]
func Eitherize0 ¶
Eitherize0 converts a function with 1 parameters returning a tuple into a function with 0 parameters returning a [ReaderIOEither[C, error, R]] The first parameter is considered to be the context [C].
func Eitherize1 ¶
Eitherize1 converts a function with 2 parameters returning a tuple into a function with 1 parameters returning a [ReaderIOEither[C, error, R]] The first parameter is considered to be the context [C].
func Eitherize10 ¶
func Eitherize10[F ~func(C, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, C, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) ReaderIOEither[C, error, R]
Eitherize10 converts a function with 11 parameters returning a tuple into a function with 10 parameters returning a [ReaderIOEither[C, error, R]] The first parameter is considered to be the context [C].
func Eitherize2 ¶
func Eitherize2[F ~func(C, T0, T1) (R, error), T0, T1, C, R any](f F) func(T0, T1) ReaderIOEither[C, error, R]
Eitherize2 converts a function with 3 parameters returning a tuple into a function with 2 parameters returning a [ReaderIOEither[C, error, R]] The first parameter is considered to be the context [C].
func Eitherize3 ¶
func Eitherize3[F ~func(C, T0, T1, T2) (R, error), T0, T1, T2, C, R any](f F) func(T0, T1, T2) ReaderIOEither[C, error, R]
Eitherize3 converts a function with 4 parameters returning a tuple into a function with 3 parameters returning a [ReaderIOEither[C, error, R]] The first parameter is considered to be the context [C].
func Eitherize4 ¶
func Eitherize4[F ~func(C, T0, T1, T2, T3) (R, error), T0, T1, T2, T3, C, R any](f F) func(T0, T1, T2, T3) ReaderIOEither[C, error, R]
Eitherize4 converts a function with 5 parameters returning a tuple into a function with 4 parameters returning a [ReaderIOEither[C, error, R]] The first parameter is considered to be the context [C].
func Eitherize5 ¶
func Eitherize5[F ~func(C, T0, T1, T2, T3, T4) (R, error), T0, T1, T2, T3, T4, C, R any](f F) func(T0, T1, T2, T3, T4) ReaderIOEither[C, error, R]
Eitherize5 converts a function with 6 parameters returning a tuple into a function with 5 parameters returning a [ReaderIOEither[C, error, R]] The first parameter is considered to be the context [C].
func Eitherize6 ¶
func Eitherize6[F ~func(C, T0, T1, T2, T3, T4, T5) (R, error), T0, T1, T2, T3, T4, T5, C, R any](f F) func(T0, T1, T2, T3, T4, T5) ReaderIOEither[C, error, R]
Eitherize6 converts a function with 7 parameters returning a tuple into a function with 6 parameters returning a [ReaderIOEither[C, error, R]] The first parameter is considered to be the context [C].
func Eitherize7 ¶
func Eitherize7[F ~func(C, T0, T1, T2, T3, T4, T5, T6) (R, error), T0, T1, T2, T3, T4, T5, T6, C, R any](f F) func(T0, T1, T2, T3, T4, T5, T6) ReaderIOEither[C, error, R]
Eitherize7 converts a function with 8 parameters returning a tuple into a function with 7 parameters returning a [ReaderIOEither[C, error, R]] The first parameter is considered to be the context [C].
func Eitherize8 ¶
func Eitherize8[F ~func(C, T0, T1, T2, T3, T4, T5, T6, T7) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, C, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7) ReaderIOEither[C, error, R]
Eitherize8 converts a function with 9 parameters returning a tuple into a function with 8 parameters returning a [ReaderIOEither[C, error, R]] The first parameter is considered to be the context [C].
func Eitherize9 ¶
func Eitherize9[F ~func(C, T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, C, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8) ReaderIOEither[C, error, R]
Eitherize9 converts a function with 10 parameters returning a tuple into a function with 9 parameters returning a [ReaderIOEither[C, error, R]] The first parameter is considered to be the context [C].
func Flap ¶
func Flap[R, E, B, A any](a A) func(ReaderIOEither[R, E, func(A) B]) ReaderIOEither[R, E, B]
Flap returns a function that applies a fixed value to a function in a context. This is the curried version of MonadFlap.
func Fold ¶
func Fold[R, E, A, B any](onLeft func(E) ReaderIO[R, B], onRight func(A) ReaderIO[R, B]) func(ReaderIOEither[R, E, A]) ReaderIO[R, B]
Fold handles both success and error cases, producing a ReaderIO. This is useful for converting a ReaderIOEither into a ReaderIO by handling all cases.
func From0 ¶
From0 converts a function with 1 parameters returning a tuple into a function with 0 parameters returning a [ReaderIOEither[R]] The first parameter is considered to be the context [C].
func From1 ¶
func From1[F ~func(C, T0) func() (R, error), T0, C, R any](f F) func(T0) ReaderIOEither[C, error, R]
From1 converts a function with 2 parameters returning a tuple into a function with 1 parameters returning a [ReaderIOEither[R]] The first parameter is considered to be the context [C].
func From10 ¶
func From10[F ~func(C, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) func() (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, C, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) ReaderIOEither[C, error, R]
From10 converts a function with 11 parameters returning a tuple into a function with 10 parameters returning a [ReaderIOEither[R]] The first parameter is considered to be the context [C].
func From2 ¶
func From2[F ~func(C, T0, T1) func() (R, error), T0, T1, C, R any](f F) func(T0, T1) ReaderIOEither[C, error, R]
From2 converts a function with 3 parameters returning a tuple into a function with 2 parameters returning a [ReaderIOEither[R]] The first parameter is considered to be the context [C].
func From3 ¶
func From3[F ~func(C, T0, T1, T2) func() (R, error), T0, T1, T2, C, R any](f F) func(T0, T1, T2) ReaderIOEither[C, error, R]
From3 converts a function with 4 parameters returning a tuple into a function with 3 parameters returning a [ReaderIOEither[R]] The first parameter is considered to be the context [C].
func From4 ¶
func From4[F ~func(C, T0, T1, T2, T3) func() (R, error), T0, T1, T2, T3, C, R any](f F) func(T0, T1, T2, T3) ReaderIOEither[C, error, R]
From4 converts a function with 5 parameters returning a tuple into a function with 4 parameters returning a [ReaderIOEither[R]] The first parameter is considered to be the context [C].
func From5 ¶
func From5[F ~func(C, T0, T1, T2, T3, T4) func() (R, error), T0, T1, T2, T3, T4, C, R any](f F) func(T0, T1, T2, T3, T4) ReaderIOEither[C, error, R]
From5 converts a function with 6 parameters returning a tuple into a function with 5 parameters returning a [ReaderIOEither[R]] The first parameter is considered to be the context [C].
func From6 ¶
func From6[F ~func(C, T0, T1, T2, T3, T4, T5) func() (R, error), T0, T1, T2, T3, T4, T5, C, R any](f F) func(T0, T1, T2, T3, T4, T5) ReaderIOEither[C, error, R]
From6 converts a function with 7 parameters returning a tuple into a function with 6 parameters returning a [ReaderIOEither[R]] The first parameter is considered to be the context [C].
func From7 ¶
func From7[F ~func(C, T0, T1, T2, T3, T4, T5, T6) func() (R, error), T0, T1, T2, T3, T4, T5, T6, C, R any](f F) func(T0, T1, T2, T3, T4, T5, T6) ReaderIOEither[C, error, R]
From7 converts a function with 8 parameters returning a tuple into a function with 7 parameters returning a [ReaderIOEither[R]] The first parameter is considered to be the context [C].
func From8 ¶
func From8[F ~func(C, T0, T1, T2, T3, T4, T5, T6, T7) func() (R, error), T0, T1, T2, T3, T4, T5, T6, T7, C, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7) ReaderIOEither[C, error, R]
From8 converts a function with 9 parameters returning a tuple into a function with 8 parameters returning a [ReaderIOEither[R]] The first parameter is considered to be the context [C].
func From9 ¶
func From9[F ~func(C, T0, T1, T2, T3, T4, T5, T6, T7, T8) func() (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, C, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8) ReaderIOEither[C, error, R]
From9 converts a function with 10 parameters returning a tuple into a function with 9 parameters returning a [ReaderIOEither[R]] The first parameter is considered to be the context [C].
func FromOption ¶
func FromOption[R, A, E any](onNone func() E) func(Option[A]) ReaderIOEither[R, E, A]
FromOption converts an Option to a ReaderIOEither. If the Option is None, the provided function is called to produce the error.
func FromPredicate ¶
func FromPredicate[R, E, A any](pred func(A) bool, onFalse func(A) E) func(A) ReaderIOEither[R, E, A]
FromPredicate creates a ReaderIOEither from a predicate. If the predicate returns false, the onFalse function is called to produce the error.
func FromStrictEquals ¶
func FromStrictEquals[R any, E, A comparable]() func(R) EQ.Eq[ReaderIOEither[R, E, A]]
FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
func Functor ¶
func Functor[R, E, A, B any]() functor.Functor[A, B, ReaderIOEither[R, E, A], ReaderIOEither[R, E, B]]
Functor returns the functor operations for ReaderIOEither
func GetOrElse ¶
func GetOrElse[R, E, A any](onLeft func(E) ReaderIO[R, A]) func(ReaderIOEither[R, E, A]) ReaderIO[R, A]
GetOrElse provides a default value in case of error. The default is computed lazily via a ReaderIO.
func Local ¶
func Local[E, A, R1, R2 any](f func(R2) R1) func(ReaderIOEither[R1, E, A]) ReaderIOEither[R2, E, A]
Local runs a computation with a modified context. The function f transforms the context before passing it to the computation. This is similar to Contravariant's contramap operation.
func MapLeft ¶
func MapLeft[R, A, E1, E2 any](f func(E1) E2) func(ReaderIOEither[R, E1, A]) ReaderIOEither[R, E2, A]
MapLeft returns a function that transforms the error channel. This is the curried version of MonadMapLeft.
func Monad ¶
func Monad[R, E, A, B any]() monad.Monad[A, B, ReaderIOEither[R, E, A], ReaderIOEither[R, E, B], ReaderIOEither[R, E, func(A) B]]
Monad returns the monadic operations for ReaderIOEither
func OrElse ¶
func OrElse[R, E1, A, E2 any](onLeft func(E1) ReaderIOEither[R, E2, A]) func(ReaderIOEither[R, E1, A]) ReaderIOEither[R, E2, A]
OrElse tries an alternative computation if the first one fails. The alternative can produce a different error type.
func OrLeft ¶
func OrLeft[A, E1, R, E2 any](onLeft func(E1) ReaderIO[R, E2]) func(ReaderIOEither[R, E1, A]) ReaderIOEither[R, E2, A]
OrLeft transforms the error using a ReaderIO if the computation fails. The success value is preserved unchanged.
func Pointed ¶
Pointed returns the pointed operations for ReaderIOEither
func TapReaderOptionK ¶
func TapReaderOptionK[R, A, B, E any](onNone func() E) func(readeroption.Kleisli[R, A, B]) Operator[R, E, A, A]
func Traverse ¶
func Traverse[R2, R1, E, A, B any]( f Kleisli[R1, E, A, B], ) func(ReaderIOEither[R2, E, A]) Kleisli[R2, E, R1, B]
Traverse transforms a ReaderIOEither computation by applying a function that produces another ReaderIOEither, 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 IOEither[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 ReaderIOEither[R1, E, B]
Returns:
- A function that takes a ReaderIOEither[R2, E, A] and returns a Kleisli[R2, E, R1, B], which is func(R2) ReaderIOEither[R1, E, B]
The function preserves error handling and IO effects while reordering the environment dependencies.
func TraverseArrayWithIndex ¶
func TraverseArrayWithIndex[R, E, A, B any](f func(int, A) ReaderIOEither[R, E, B]) func([]A) ReaderIOEither[R, E, []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:
- R: The context type
- E: 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 ReaderIOEither
Returns:
A function that takes an array and returns a ReaderIOEither of an array
Example:
processWithIndex := TraverseArrayWithIndex(func(i int, val string) ReaderIOEither[Config, error, string] {
return Of[Config, error](fmt.Sprintf("%d: %s", i, val))
})
Example ¶
Example of TraverseArrayWithIndex - process items with their positions
package main
import (
"fmt"
E "github.com/IBM/fp-go/v2/either"
RIE "github.com/IBM/fp-go/v2/readerioeither"
)
type Config struct {
APIKey string
BaseURL string
}
func main() {
cfg := Config{APIKey: "secret"}
items := []string{"apple", "banana", "cherry"}
processWithIndex := RIE.TraverseArrayWithIndex(func(i int, item string) RIE.ReaderIOEither[Config, error, string] {
return RIE.Of[Config, error](fmt.Sprintf("%d: %s", i+1, item))
})
result := processWithIndex(items)(cfg)()
E.Fold(
func(err error) int {
fmt.Printf("Error: %v\n", err)
return 0
},
func(processed []string) int {
for _, item := range processed {
fmt.Println(item)
}
return len(processed)
},
)(result)
}
Output: 1: apple 2: banana 3: cherry
func TraverseReader ¶
func TraverseReader[R2, R1, E, A, B any]( f reader.Kleisli[R1, A, B], ) func(ReaderIOEither[R2, E, A]) Kleisli[R2, E, R1, B]
TraverseReader transforms a ReaderIOEither computation by applying a Reader-based function, effectively introducing a new environment dependency.
This function takes a Reader-based transformation (Kleisli arrow) and returns a function that can transform a ReaderIOEither. The result allows you to provide the Reader's environment (R1) first, which then produces a ReaderIOEither that depends on environment R2.
Type Parameters:
- R2: The outer environment type (from the original ReaderIOEither)
- R1: The inner environment type (introduced by the Reader transformation)
- E: The error type
- A: The input value type
- B: The output value type
Parameters:
- f: A Reader-based Kleisli arrow that transforms A to B using environment R1
Returns:
- A function that takes a ReaderIOEither[R2, E, A] and returns a Kleisli[R2, E, R1, B], which is func(R2) ReaderIOEither[R1, E, B]
The function preserves error handling and IO effects while adding the Reader environment dependency.
Example:
type Config struct {
Multiplier int
}
type Database struct {
ConnectionString string
}
// Original computation that depends on Database
original := func(db Database) IOEither[error, int] {
return ioeither.Right[error](len(db.ConnectionString))
}
// Reader-based transformation that depends on Config
multiply := func(x int) func(Config) int {
return func(cfg Config) int {
return x * cfg.Multiplier
}
}
// Apply TraverseReader to introduce Config dependency
traversed := TraverseReader[Database, Config, error, int, int](multiply)
result := traversed(original)
// Provide Config first, then Database
cfg := Config{Multiplier: 5}
db := Database{ConnectionString: "localhost:5432"}
finalResult := result(cfg)(db)() // Returns Right(80) = len("localhost:5432") * 5
func TraverseRecord ¶
func TraverseRecord[K comparable, R, E, A, B any](f func(A) ReaderIOEither[R, E, B]) func(map[K]A) ReaderIOEither[R, E, map[K]B]
TraverseRecord transforms each value in a map using a function that returns a ReaderIOEither, then collects the results into a single ReaderIOEither containing a map.
If any transformation fails, the entire operation fails with the first error encountered. The keys are preserved in the output map.
Type parameters:
- R: The context type
- K: The key type (must be comparable)
- E: The error type
- A: The input value type
- B: The output value type
Parameters:
- f: A function that transforms each value into a ReaderIOEither
Returns:
A function that takes a map and returns a ReaderIOEither of a map
Example:
enrichUsers := TraverseRecord(func(user User) ReaderIOEither[Config, error, EnrichedUser] {
return enrichUser(user)
})
result := enrichUsers(map[string]User{"alice": user1, "bob": user2})
func TraverseRecordWithIndex ¶
func TraverseRecordWithIndex[K comparable, R, E, A, B any](f func(K, A) ReaderIOEither[R, E, B]) func(map[K]A) ReaderIOEither[R, E, map[K]B]
TraverseRecordWithIndex is like TraverseRecord but the transformation function also receives the key.
This is useful when the transformation depends on the key associated with each value.
Type parameters:
- R: The context type
- K: The key type (must be comparable)
- E: The error type
- A: The input value type
- B: The output value type
Parameters:
- f: A function that transforms each key-value pair into a ReaderIOEither
Returns:
A function that takes a map and returns a ReaderIOEither of a map
Example:
processWithKey := TraverseRecordWithIndex(func(key string, val int) ReaderIOEither[Config, error, string] {
return Of[Config, error](fmt.Sprintf("%s: %d", key, val))
})
func Uneitherize0 ¶
Uneitherize0 converts a function with 1 parameters returning a [ReaderIOEither[C, error, R]] into a function with 0 parameters returning a tuple. The first parameter is considered to be the context [C].
func Uneitherize1 ¶
func Uneitherize1[F ~func(T0) ReaderIOEither[C, error, R], T0, C, R any](f F) func(C, T0) (R, error)
Uneitherize1 converts a function with 2 parameters returning a [ReaderIOEither[C, error, R]] into a function with 1 parameters returning a tuple. The first parameter is considered to be the context [C].
func Uneitherize10 ¶
func Uneitherize10[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) ReaderIOEither[C, error, R], T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, C, R any](f F) func(C, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error)
Uneitherize10 converts a function with 11 parameters returning a [ReaderIOEither[C, error, R]] into a function with 10 parameters returning a tuple. The first parameter is considered to be the context [C].
func Uneitherize2 ¶
func Uneitherize2[F ~func(T0, T1) ReaderIOEither[C, error, R], T0, T1, C, R any](f F) func(C, T0, T1) (R, error)
Uneitherize2 converts a function with 3 parameters returning a [ReaderIOEither[C, error, R]] into a function with 2 parameters returning a tuple. The first parameter is considered to be the context [C].
func Uneitherize3 ¶
func Uneitherize3[F ~func(T0, T1, T2) ReaderIOEither[C, error, R], T0, T1, T2, C, R any](f F) func(C, T0, T1, T2) (R, error)
Uneitherize3 converts a function with 4 parameters returning a [ReaderIOEither[C, error, R]] into a function with 3 parameters returning a tuple. The first parameter is considered to be the context [C].
func Uneitherize4 ¶
func Uneitherize4[F ~func(T0, T1, T2, T3) ReaderIOEither[C, error, R], T0, T1, T2, T3, C, R any](f F) func(C, T0, T1, T2, T3) (R, error)
Uneitherize4 converts a function with 5 parameters returning a [ReaderIOEither[C, error, R]] into a function with 4 parameters returning a tuple. The first parameter is considered to be the context [C].
func Uneitherize5 ¶
func Uneitherize5[F ~func(T0, T1, T2, T3, T4) ReaderIOEither[C, error, R], T0, T1, T2, T3, T4, C, R any](f F) func(C, T0, T1, T2, T3, T4) (R, error)
Uneitherize5 converts a function with 6 parameters returning a [ReaderIOEither[C, error, R]] into a function with 5 parameters returning a tuple. The first parameter is considered to be the context [C].
func Uneitherize6 ¶
func Uneitherize6[F ~func(T0, T1, T2, T3, T4, T5) ReaderIOEither[C, error, R], T0, T1, T2, T3, T4, T5, C, R any](f F) func(C, T0, T1, T2, T3, T4, T5) (R, error)
Uneitherize6 converts a function with 7 parameters returning a [ReaderIOEither[C, error, R]] into a function with 6 parameters returning a tuple. The first parameter is considered to be the context [C].
func Uneitherize7 ¶
func Uneitherize7[F ~func(T0, T1, T2, T3, T4, T5, T6) ReaderIOEither[C, error, R], T0, T1, T2, T3, T4, T5, T6, C, R any](f F) func(C, T0, T1, T2, T3, T4, T5, T6) (R, error)
Uneitherize7 converts a function with 8 parameters returning a [ReaderIOEither[C, error, R]] into a function with 7 parameters returning a tuple. The first parameter is considered to be the context [C].
func Uneitherize8 ¶
func Uneitherize8[F ~func(T0, T1, T2, T3, T4, T5, T6, T7) ReaderIOEither[C, error, R], T0, T1, T2, T3, T4, T5, T6, T7, C, R any](f F) func(C, T0, T1, T2, T3, T4, T5, T6, T7) (R, error)
Uneitherize8 converts a function with 9 parameters returning a [ReaderIOEither[C, error, R]] into a function with 8 parameters returning a tuple. The first parameter is considered to be the context [C].
func Uneitherize9 ¶
func Uneitherize9[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8) ReaderIOEither[C, error, R], T0, T1, T2, T3, T4, T5, T6, T7, T8, C, R any](f F) func(C, T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error)
Uneitherize9 converts a function with 10 parameters returning a [ReaderIOEither[C, error, R]] into a function with 9 parameters returning a tuple. The first parameter is considered to be the context [C].
Types ¶
type Either ¶
Either represents a value of one of two possible types (a disjoint union). An instance of Either is either Left (representing an error) or Right (representing a success).
type IOEither ¶
IOEither represents a computation that performs side effects and can either fail with an error of type E or succeed with a value of type A.
type Kleisli ¶
type Kleisli[R, E, A, B any] = reader.Reader[A, ReaderIOEither[R, E, B]]
func FromReaderOption ¶
func FromReaderOption[R, A, E any](onNone func() E) Kleisli[R, E, ReaderOption[R, A], A]
func ReduceArray ¶
func ReduceArray[R, E, A, B any](reduce func(B, A) B, initial B) Kleisli[R, E, []ReaderIOEither[R, E, A], B]
func ReduceArrayM ¶
func Sequence ¶
func Sequence[R1, R2, E, A any](ma ReaderIOEither[R2, E, ReaderIOEither[R1, E, A]]) Kleisli[R2, E, R1, A]
Sequence swaps the order of nested environment parameters in a ReaderIOEither computation.
This function takes a ReaderIOEither that produces another ReaderIOEither 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 IOEither[E, A].
Type Parameters:
- R1: The first environment type (becomes inner after sequence)
- R2: The second environment type (becomes outer after sequence)
- E: The error type
- A: The success value type
Parameters:
- ma: A ReaderIOEither that takes R2 and may produce a ReaderIOEither[R1, E, A]
Returns:
- A Kleisli[R2, E, R1, A], which is func(R2) func(R1) IOEither[E, A]
The function preserves error handling and IO effects at both levels.
func SequenceReader ¶
func SequenceReader[R1, R2, E, A any](ma ReaderIOEither[R2, E, Reader[R1, A]]) Kleisli[R2, E, R1, A]
SequenceReader swaps the order of environment parameters when the inner computation is a pure Reader.
This function is similar to Sequence but specialized for the case where the innermost computation is a pure Reader (without IO or error handling) rather than another ReaderIOEither.
Type Parameters:
- R1: The first environment type (becomes outer after sequence)
- R2: The second environment type (becomes inner after sequence)
- E: The error type (only present in the ReaderIOEither layer)
- A: The success value type
Parameters:
- ma: A ReaderIOEither that takes R2 and may produce a Reader[R1, A]
Returns:
- A Kleisli[R2, E, R1, A], which is func(R2) func(R1) IOEither[E, A]
func SequenceReaderEither ¶
func SequenceReaderEither[R1, R2, E, A any](ma ReaderIOEither[R2, E, ReaderEither[R1, E, A]]) Kleisli[R2, E, R1, A]
SequenceReaderEither swaps the order of environment parameters when the inner computation is a ReaderEither.
This function is specialized for the case where the innermost computation is a ReaderEither (with error handling but no IO effects) rather than another ReaderIOEither.
Type Parameters:
- R1: The first environment type (becomes outer after sequence)
- R2: The second environment type (becomes inner after sequence)
- E: The error type (present in both layers)
- A: The success value type
Parameters:
- ma: A ReaderIOEither that takes R2 and may produce a ReaderEither[R1, E, A]
Returns:
- A Kleisli[R2, E, R1, A], which is func(R2) func(R1) IOEither[E, A]
func SequenceReaderIO ¶
func SequenceReaderIO[R1, R2, E, A any](ma ReaderIOEither[R2, E, ReaderIO[R1, A]]) Kleisli[R2, E, R1, A]
SequenceReaderIO swaps the order of environment parameters when the inner computation is a ReaderIO.
This function is specialized for the case where the innermost computation is a ReaderIO (with IO effects but no error handling) rather than another ReaderIOEither.
Type Parameters:
- R1: The first environment type (becomes outer after sequence)
- R2: The second environment type (becomes inner after sequence)
- E: The error type (only present in the outer ReaderIOEither layer)
- A: The success value type
Parameters:
- ma: A ReaderIOEither that takes R2 and may produce a ReaderIO[R1, A]
Returns:
- A Kleisli[R2, E, R1, A], which is func(R2) func(R1) IOEither[E, A]
func TailRec ¶
func TailRec[R, E, A, B any](f Kleisli[R, E, A, tailrec.Trampoline[A, B]]) Kleisli[R, E, A, B]
TailRec implements stack-safe tail recursion for the ReaderIOEither monad.
This function enables recursive computations that combine three powerful concepts:
- Environment dependency (Reader aspect): Access to configuration, context, or dependencies
- Side effects (IO aspect): Logging, file I/O, network calls, etc.
- Error handling (Either aspect): Computations that can fail with an error
The function uses an iterative loop to execute the recursion, making it safe for deep or unbounded recursion without risking stack overflow.
How It Works ¶
TailRec takes a Kleisli arrow that returns IOEither[E, Trampoline[A, B]]:
- Left(E): Computation failed with error E - recursion terminates
- Right(Bounce(A)): Continue recursion with the new state A
- Right(Land(B)): Terminate recursion successfully and return the final result B
The function iteratively applies the Kleisli arrow, passing the environment R to each iteration, until either an error (Left) or a final result (Right(Right(B))) is produced.
Type Parameters ¶
- R: The environment type (Reader context) - e.g., Config, Logger, Database connection
- E: The error type that can occur during computation
- A: The state type that changes during recursion
- B: The final result type when recursion terminates successfully
Parameters ¶
- f: A Kleisli arrow (A => ReaderIOEither[R, E, Either[A, B]]) that:
- Takes the current state A
- Returns a ReaderIOEither that depends on environment R
- Can fail with error E (Left)
- Produces Either[A, B] to control recursion flow (Right)
Returns ¶
A Kleisli arrow (A => ReaderIOEither[R, E, B]) that:
- Takes an initial state A
- Returns a ReaderIOEither that requires environment R
- Can fail with error E
- Produces the final result B after recursion completes
Comparison with Other Monads ¶
Compared to other tail recursion implementations:
- Like IOEither: Has error handling (Left for errors)
- Like ReaderIO: Has environment dependency (R passed to each iteration)
- Unlike IOOption: Uses Either for both errors and recursion control
- Most powerful: Combines all three aspects (Reader + IO + Either)
Use Cases ¶
Environment-dependent recursive algorithms with error handling: - Recursive computations that need configuration and can fail - Algorithms that log progress and handle errors gracefully - Recursive operations with retry logic based on environment settings
Stateful computations with context and error handling: - Tree traversals that need environment context and can fail - Graph algorithms with configuration-dependent behavior and error cases - Recursive parsers with environment-based rules and error reporting
Recursive operations with side effects and error handling: - File system traversals with logging and error handling - Network operations with retry configuration and failure handling - Database operations with connection pooling and error recovery
Example: Factorial with Logging and Error Handling ¶
type Env struct {
Logger func(string)
MaxN int
}
type State struct {
n int
acc int
}
// Factorial that logs each step and validates input
factorialStep := func(state State) readerioeither.ReaderIOEither[Env, string, tailrec.Trampoline[State, int]] {
return func(env Env) ioeither.IOEither[string, tailrec.Trampoline[State, int]] {
return func() either.Either[string, tailrec.Trampoline[State, int]] {
if state.n > env.MaxN {
return either.Left[tailrec.Trampoline[State, int]](fmt.Sprintf("n too large: %d > %d", state.n, env.MaxN))
}
if state.n <= 0 {
env.Logger(fmt.Sprintf("Factorial complete: %d", state.acc))
return either.Right[string](tailrec.Land[State](state.acc))
}
env.Logger(fmt.Sprintf("Computing: %d * %d", state.n, state.acc))
return either.Right[string](tailrec.Bounce[int](State{state.n - 1, state.acc * state.n}))
}
}
}
factorial := readerioeither.TailRec(factorialStep)
env := Env{Logger: func(msg string) { fmt.Println(msg) }, MaxN: 20}
result := factorial(State{5, 1})(env)() // Returns Right(120), logs each step
// If n > MaxN, returns Left("n too large: ...")
Example: File Processing with Error Handling ¶
type Config struct {
MaxRetries int
Logger func(string)
}
type ProcessState struct {
files []string
results []string
retries int
}
processFilesStep := func(state ProcessState) readerioeither.ReaderIOEither[Config, error, tailrec.Trampoline[ProcessState, []string]] {
return func(cfg Config) ioeither.IOEither[error, tailrec.Trampoline[ProcessState, []string]] {
return func() either.Either[error, tailrec.Trampoline[ProcessState, []string]] {
if len(state.files) == 0 {
cfg.Logger("All files processed")
return either.Right[error](tailrec.Land[ProcessState](state.results))
}
file := state.files[0]
cfg.Logger(fmt.Sprintf("Processing: %s", file))
// Simulate file processing that might fail
if err := processFile(file); err != nil {
if state.retries >= cfg.MaxRetries {
return either.Left[tailrec.Trampoline[ProcessState, []string]](
fmt.Errorf("max retries exceeded for %s: %w", file, err))
}
cfg.Logger(fmt.Sprintf("Retry %d for %s", state.retries+1, file))
return either.Right[error](tailrec.Bounce[[]string](ProcessState{
files: state.files,
results: state.results,
retries: state.retries + 1,
}))
}
return either.Right[error](tailrec.Bounce[[]string](ProcessState{
files: state.files[1:],
results: append(state.results, file),
retries: 0,
}))
}
}
}
processFiles := readerioeither.TailRec(processFilesStep)
config := Config{MaxRetries: 3, Logger: func(msg string) { fmt.Println(msg) }}
result := processFiles(ProcessState{files: []string{"a.txt", "b.txt"}, results: []string{}, retries: 0})(config)()
// Returns Right([]string{"a.txt", "b.txt"}) on success
// Returns Left(error) if max retries exceeded
Stack Safety ¶
The iterative implementation ensures that even deeply recursive computations (thousands or millions of iterations) will not cause stack overflow:
// Safe for very large inputs
countdownStep := func(n int) readerioeither.ReaderIOEither[Env, error, tailrec.Trampoline[int, int]] {
return func(env Env) ioeither.IOEither[error, tailrec.Trampoline[int, int]] {
return func() either.Either[error, tailrec.Trampoline[int, int]] {
if n <= 0 {
return either.Right[error](tailrec.Land[int](0))
}
return either.Right[error](tailrec.Bounce[int](n - 1))
}
}
}
countdown := readerioeither.TailRec(countdownStep)
result := countdown(1000000)(env)() // Safe, no stack overflow
Error Handling Patterns ¶
The Either[E, Trampoline[A, B]] structure provides two levels of control:
Outer Either (Left(E)): Unrecoverable errors that terminate recursion - Validation failures - Resource exhaustion - Fatal errors
Inner Trampoline (Right(Bounce(A)) or Right(Land(B))): Recursion control - Bounce(A): Continue with new state - Land(B): Terminate successfully
This separation allows for:
- Early termination on errors
- Graceful error propagation
- Clear distinction between "continue" and "error" states
Performance Considerations ¶
- Each iteration creates a new IOEither action by calling f(a)(r)()
- The environment R is passed to every iteration
- Error checking happens on each iteration (Left vs Right)
- For performance-critical code, consider if error handling is necessary at each step
- Memoization of environment-derived values may improve performance
See Also ¶
- ioeither.TailRec: Tail recursion with error handling (no environment)
- readerio.TailRec: Tail recursion with environment (no error handling)
- [iooption.TailRec]: Tail recursion with optional results
- Chain: For sequencing ReaderIOEither computations
- Ask: For accessing the environment
- Left/Right: For creating error/success values
func TraverseArray ¶
func TraverseArray[R, E, A, B any](f Kleisli[R, E, A, B]) Kleisli[R, E, []A, []B]
TraverseArray transforms each element of an array using a function that returns a ReaderIOEither, then collects the results into a single ReaderIOEither containing an array.
If any transformation fails, the entire operation fails with the first error encountered. All transformations are executed sequentially.
Type parameters:
- R: The context type
- E: The error type
- A: The input element type
- B: The output element type
Parameters:
- f: A function that transforms each element into a ReaderIOEither
Returns:
A function that takes an array and returns a ReaderIOEither of an array
Example:
fetchUsers := TraverseArray(func(id int) ReaderIOEither[Config, error, User] {
return fetchUser(id)
})
result := fetchUsers([]int{1, 2, 3})
// result(cfg)() returns Right([user1, user2, user3]) or Left(error)
Example ¶
Example of TraverseArray - fetch multiple users
package main
import (
"fmt"
E "github.com/IBM/fp-go/v2/either"
RIE "github.com/IBM/fp-go/v2/readerioeither"
S "github.com/IBM/fp-go/v2/string"
)
type Config struct {
APIKey string
BaseURL string
}
type User struct {
ID int
Name string
}
// Simulate fetching a user by ID
func fetchUser(id int) RIE.ReaderIOEither[Config, error, User] {
return func(cfg Config) func() E.Either[error, User] {
return func() E.Either[error, User] {
if S.IsEmpty(cfg.APIKey) {
return E.Left[User](fmt.Errorf("missing API key"))
}
if id <= 0 {
return E.Left[User](fmt.Errorf("invalid user ID: %d", id))
}
return E.Right[error](User{ID: id, Name: fmt.Sprintf("User%d", id)})
}
}
}
func main() {
cfg := Config{APIKey: "secret", BaseURL: "https://api.example.com"}
// Fetch users with IDs 1, 2, 3
userIDs := []int{1, 2, 3}
fetchUsers := RIE.TraverseArray(fetchUser)
result := fetchUsers(userIDs)(cfg)()
E.Fold(
func(err error) string {
fmt.Println("Failed to fetch users")
return ""
},
func(users []User) string {
fmt.Println("Successfully fetched all users")
return ""
},
)(result)
}
Output: Successfully fetched all users
Example (ErrorHandling) ¶
Example showing error handling with TraverseArray
package main
import (
"fmt"
E "github.com/IBM/fp-go/v2/either"
RIE "github.com/IBM/fp-go/v2/readerioeither"
S "github.com/IBM/fp-go/v2/string"
)
type Config struct {
APIKey string
BaseURL string
}
type User struct {
ID int
Name string
}
// Simulate fetching a user by ID
func fetchUser(id int) RIE.ReaderIOEither[Config, error, User] {
return func(cfg Config) func() E.Either[error, User] {
return func() E.Either[error, User] {
if S.IsEmpty(cfg.APIKey) {
return E.Left[User](fmt.Errorf("missing API key"))
}
if id <= 0 {
return E.Left[User](fmt.Errorf("invalid user ID: %d", id))
}
return E.Right[error](User{ID: id, Name: fmt.Sprintf("User%d", id)})
}
}
}
func main() {
cfg := Config{APIKey: "secret"}
// One invalid ID will cause the entire operation to fail
userIDs := []int{1, -1, 3} // -1 is invalid
fetchUsers := RIE.TraverseArray(fetchUser)
result := fetchUsers(userIDs)(cfg)()
E.Fold(
func(err error) string {
fmt.Printf("Failed: %v\n", err)
return ""
},
func(users []User) string {
fmt.Printf("Success: fetched %d users\n", len(users))
return ""
},
)(result)
}
Output: Failed: invalid user ID: -1
Example (Pipeline) ¶
Example of combining Traverse with other operations
package main
import (
"fmt"
E "github.com/IBM/fp-go/v2/either"
F "github.com/IBM/fp-go/v2/function"
RIE "github.com/IBM/fp-go/v2/readerioeither"
S "github.com/IBM/fp-go/v2/string"
)
type Config struct {
APIKey string
BaseURL string
}
type User struct {
ID int
Name string
}
// Simulate fetching a user by ID
func fetchUser(id int) RIE.ReaderIOEither[Config, error, User] {
return func(cfg Config) func() E.Either[error, User] {
return func() E.Either[error, User] {
if S.IsEmpty(cfg.APIKey) {
return E.Left[User](fmt.Errorf("missing API key"))
}
if id <= 0 {
return E.Left[User](fmt.Errorf("invalid user ID: %d", id))
}
return E.Right[error](User{ID: id, Name: fmt.Sprintf("User%d", id)})
}
}
}
func main() {
cfg := Config{APIKey: "secret"}
// Pipeline: fetch users, then extract their names
userIDs := []int{1, 2}
pipeline := F.Pipe2(
userIDs,
RIE.TraverseArray(fetchUser),
RIE.Map[Config, error](func(users []User) []string {
names := make([]string, len(users))
for i, user := range users {
names[i] = user.Name
}
return names
}),
)
result := pipeline(cfg)()
E.Fold(
func(err error) string {
fmt.Printf("Error: %v\n", err)
return ""
},
func(names []string) string {
fmt.Printf("User names: %v\n", names)
return ""
},
)(result)
}
Output: User names: [User1 User2]
func TraverseReduceArray ¶
func TraverseReduceArray[R, E, A, B, C any](trfrm Kleisli[R, E, A, B], reduce func(C, B) C, initial C) Kleisli[R, E, []A, C]
func TraverseReduceArrayM ¶
func WithResource ¶
func WithResource[A, L, E, R, ANY any](onCreate ReaderIOEither[L, E, R], onRelease Kleisli[L, E, R, ANY]) Kleisli[L, E, Kleisli[L, E, R, A], A]
WithResource constructs a function that creates a resource, operates on it, and then releases the resource. This ensures proper resource cleanup even in the presence of errors, following the Resource Acquisition Is Initialization (RAII) pattern.
The resource lifecycle is:
- onCreate: Acquires the resource
- use: Operates on the resource (provided as argument to the returned function)
- onRelease: Releases the resource (called regardless of success or failure)
Type parameters:
- A: The type of the result produced by using the resource
- L: The context type
- E: The error type
- R: The resource type
- ANY: The type returned by the release function (typically ignored)
Parameters:
- onCreate: A computation that acquires the resource
- onRelease: A function that releases the resource, called with the resource and executed regardless of errors
Returns:
A function that takes a resource-using function and returns a ReaderIOEither that manages the resource lifecycle
Example:
withFile := WithResource(
openFile("data.txt"),
func(f *File) ReaderIOEither[Config, error, int] {
return closeFile(f)
},
)
result := withFile(func(f *File) ReaderIOEither[Config, error, string] {
return readContent(f)
})
type Monoid ¶
func AltMonoid ¶
AltMonoid is the alternative Monoid for a [ReaderIOResult]. This creates a monoid where the empty value is provided lazily, and combination uses the Alt operation (try first, fallback to second on failure).
Parameters:
- zero: Lazy computation that provides the empty/identity value
Returns a Monoid for ReaderIOResult[A] with Alt-based combination.
func AlternativeMonoid ¶
AlternativeMonoid is the alternative Monoid for [ReaderIOResult]. This combines ReaderIOResult values using the alternative semantics, where the second value is only evaluated if the first fails.
Parameters:
- m: The underlying monoid for type A
Returns a Monoid for ReaderIOResult[A] with alternative semantics.
func ApplicativeMonoid ¶
ApplicativeMonoid returns a Monoid that concatenates [ReaderIOResult] instances via their applicative. This uses the default applicative behavior (parallel or sequential based on useParallel flag).
The monoid combines two ReaderIOResult values by applying the underlying monoid's combine operation to their success values using applicative application.
Parameters:
- m: The underlying monoid for type A
Returns a Monoid for ReaderIOResult[A].
func ApplicativeMonoidPar ¶
ApplicativeMonoidPar returns a Monoid that concatenates [ReaderIOResult] instances via their applicative. This explicitly uses parallel execution for combining values.
Parameters:
- m: The underlying monoid for type A
Returns a Monoid for ReaderIOResult[A] with parallel execution.
func ApplicativeMonoidSeq ¶
ApplicativeMonoidSeq returns a Monoid that concatenates [ReaderIOResult] instances via their applicative. This explicitly uses sequential execution for combining values.
Parameters:
- m: The underlying monoid for type A
Returns a Monoid for ReaderIOResult[A] with sequential execution.
type Operator ¶
type Operator[R, E, A, B any] = Kleisli[R, E, ReaderIOEither[R, E, A], B]
Operator represents a transformation from one ReaderIOEither to another. It's a Reader that takes a ReaderIOEither[R, E, A] and produces a ReaderIOEither[R, E, B]. This type is commonly used for composing operations in a point-free style.
Type parameters:
- R: The context type
- E: The error type
- A: The input value type
- B: The output value type
Example:
var doubleOp Operator[Config, error, int, int] = Map(N.Mul(2))
func Alt ¶
Alt returns a function that tries an alternative computation if the first fails. This is the curried version of MonadAlt.
func ApEitherS ¶
func ApEitherS[R, E, S1, S2, T any]( setter func(T) func(S1) S2, fa Either[E, T], ) Operator[R, E, S1, S2]
ApEitherS is an applicative variant that works with Either values. It lifts an Either value into the ReaderIOEither context using applicative composition.
Parameters:
- setter: Updates state from S1 to S2 using result T
- fa: An Either value
func ApEitherSL ¶
ApEitherSL is a lens-based variant of ApEitherS. It combines a lens with an Either value using applicative composition.
Parameters:
- lens: A lens focusing on field T within state S
- fa: An Either value
func ApIOEitherS ¶
func ApIOEitherS[R, E, S1, S2, T any]( setter func(T) func(S1) S2, fa IOEither[E, T], ) Operator[R, E, S1, S2]
ApIOEitherS is an applicative variant that works with IOEither values. Unlike BindIOEitherK, this uses applicative composition (ApS) instead of monadic composition (Bind), allowing independent computations to be combined.
Parameters:
- setter: Updates state from S1 to S2 using result T
- fa: An IOEither value
func ApIOEitherSL ¶
ApIOEitherSL is a lens-based variant of ApIOEitherS. It combines a lens with an IOEither value using applicative composition.
Parameters:
- lens: A lens focusing on field T within state S
- fa: An IOEither value
func ApIOS ¶
func ApIOS[R, E, S1, S2, T any]( setter func(T) func(S1) S2, fa IO[T], ) Operator[R, E, S1, S2]
ApIOS is an applicative variant that works with IO values. It lifts an IO value into the ReaderIOEither context using applicative composition.
Parameters:
- setter: Updates state from S1 to S2 using result T
- fa: An IO value
func ApIOSL ¶
ApIOSL is a lens-based variant of ApIOS. It combines a lens with an IO value using applicative composition.
Parameters:
- lens: A lens focusing on field T within state S
- fa: An IO value
func ApReaderIOS ¶
func ApReaderIOS[R, E, S1, S2, T any]( setter func(T) func(S1) S2, fa ReaderIO[R, T], ) Operator[R, E, S1, S2]
ApReaderIOS is an applicative variant that works with ReaderIO values. It lifts a ReaderIO value into the ReaderIOEither context using applicative composition.
Parameters:
- setter: Updates state from S1 to S2 using result T
- fa: A ReaderIO value
func ApReaderIOSL ¶
ApReaderIOSL is a lens-based variant of ApReaderIOS. It combines a lens with a ReaderIO value using applicative composition.
Parameters:
- lens: A lens focusing on field T within state S
- fa: A ReaderIO value
func ApReaderS ¶
func ApReaderS[R, E, S1, S2, T any]( setter func(T) func(S1) S2, fa Reader[R, T], ) Operator[R, E, S1, S2]
ApReaderS is an applicative variant that works with Reader values. It lifts a Reader value into the ReaderIOEither context using applicative composition.
Parameters:
- setter: Updates state from S1 to S2 using result T
- fa: A Reader value
func ApReaderSL ¶
ApReaderSL is a lens-based variant of ApReaderS. It combines a lens with a Reader value using applicative composition.
Parameters:
- lens: A lens focusing on field T within state S
- fa: A Reader value
func ApS ¶
func ApS[R, E, S1, S2, T any]( setter func(T) func(S1) S2, fa ReaderIOEither[R, E, T], ) Operator[R, E, S1, 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
Posts []Post
}
type Env struct {
UserRepo UserRepository
PostRepo PostRepository
}
// These operations are independent and can be combined with ApS
getUser := readerioeither.Asks(func(env Env) ioeither.IOEither[error, User] {
return env.UserRepo.FindUser()
})
getPosts := readerioeither.Asks(func(env Env) ioeither.IOEither[error, []Post] {
return env.PostRepo.FindPosts()
})
result := F.Pipe2(
readerioeither.Do[Env, error](State{}),
readerioeither.ApS(
func(user User) func(State) State {
return func(s State) State { s.User = user; return s }
},
getUser,
),
readerioeither.ApS(
func(posts []Post) func(State) State {
return func(s State) State { s.Posts = posts; return s }
},
getPosts,
),
)
func ApSL ¶
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
Posts []Post
}
type Env struct {
UserRepo UserRepository
PostRepo PostRepository
}
userLens := lens.MakeLens(
func(s State) User { return s.User },
func(s State, u User) State { s.User = u; return s },
)
getUser := readerioeither.Asks(func(env Env) ioeither.IOEither[error, User] {
return env.UserRepo.FindUser()
})
result := F.Pipe2(
readerioeither.Of[Env, error](State{}),
readerioeither.ApSL(userLens, getUser),
)
func Bind ¶
func Bind[R, E, S1, S2, T any]( setter func(T) func(S1) S2, f func(S1) ReaderIOEither[R, E, T], ) Operator[R, E, S1, 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
Posts []Post
}
type Env struct {
UserRepo UserRepository
PostRepo PostRepository
}
result := F.Pipe2(
readerioeither.Do[Env, error](State{}),
readerioeither.Bind(
func(user User) func(State) State {
return func(s State) State { s.User = user; return s }
},
func(s State) readerioeither.ReaderIOEither[Env, error, User] {
return readerioeither.Asks(func(env Env) ioeither.IOEither[error, User] {
return env.UserRepo.FindUser()
})
},
),
readerioeither.Bind(
func(posts []Post) func(State) State {
return func(s State) State { s.Posts = posts; return s }
},
func(s State) readerioeither.ReaderIOEither[Env, error, []Post] {
// This can access s.User from the previous step
return readerioeither.Asks(func(env Env) ioeither.IOEither[error, []Post] {
return env.PostRepo.FindPostsByUser(s.User.ID)
})
},
),
)
func BindEitherK ¶
func BindEitherK[R, E, S1, S2, T any]( setter func(T) func(S1) S2, f either.Kleisli[E, S1, T], ) Operator[R, E, S1, S2]
BindEitherK is a variant of Bind that works with Either computations. It lifts an Either Kleisli arrow into the ReaderIOEither context.
Parameters:
- setter: Updates state from S1 to S2 using result T
- f: An Either Kleisli arrow (S1 -> Either[E, T])
func BindIOEitherK ¶
func BindIOEitherK[R, E, S1, S2, T any]( setter func(T) func(S1) S2, f ioeither.Kleisli[E, S1, T], ) Operator[R, E, S1, S2]
BindIOEitherK is a variant of Bind that works with IOEither computations. It lifts an IOEither Kleisli arrow into the ReaderIOEither context, allowing you to compose IOEither operations within a do-notation chain.
Parameters:
- setter: Updates state from S1 to S2 using result T
- f: An IOEither Kleisli arrow (S1 -> IOEither[E, T])
Returns:
- An Operator that can be used in a do-notation chain
func BindIOEitherKL ¶
func BindIOEitherKL[R, E, S, T any]( lens L.Lens[S, T], f ioeither.Kleisli[E, T, T], ) Operator[R, E, S, S]
BindIOEitherKL is a lens-based variant of BindIOEitherK. It combines a lens with an IOEither Kleisli arrow, focusing on a specific field within the state structure.
Parameters:
- lens: A lens focusing on field T within state S
- f: An IOEither Kleisli arrow (T -> IOEither[E, T])
func BindIOK ¶
func BindIOK[R, E, S1, S2, T any]( setter func(T) func(S1) S2, f io.Kleisli[S1, T], ) Operator[R, E, S1, S2]
BindIOK is a variant of Bind that works with IO computations. It lifts an IO Kleisli arrow into the ReaderIOEither context.
Parameters:
- setter: Updates state from S1 to S2 using result T
- f: An IO Kleisli arrow (S1 -> IO[T])
func BindIOKL ¶
BindIOKL is a lens-based variant of BindIOK. It combines a lens with an IO Kleisli arrow, focusing on a specific field within the state structure.
Parameters:
- lens: A lens focusing on field T within state S
- f: An IO Kleisli arrow (T -> IO[T])
func BindL ¶
func BindL[R, E, S, T any]( lens L.Lens[S, T], f func(T) ReaderIOEither[R, E, T], ) Operator[R, E, S, 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 ReaderIOEither computation that produces an updated value.
Example:
type State struct {
User User
Posts []Post
}
type Env struct {
UserRepo UserRepository
PostRepo PostRepository
}
userLens := lens.MakeLens(
func(s State) User { return s.User },
func(s State, u User) State { s.User = u; return s },
)
result := F.Pipe2(
readerioeither.Do[Env, error](State{}),
readerioeither.BindL(userLens, func(user User) readerioeither.ReaderIOEither[Env, error, User] {
return readerioeither.Asks(func(env Env) ioeither.IOEither[error, User] {
return env.UserRepo.FindUser()
})
}),
)
func BindReaderIOK ¶
func BindReaderIOK[E, R, S1, S2, T any]( setter func(T) func(S1) S2, f readerio.Kleisli[R, S1, T], ) Operator[R, E, S1, S2]
BindReaderIOK is a variant of Bind that works with ReaderIO computations. It lifts a ReaderIO Kleisli arrow into the ReaderIOEither context.
Parameters:
- setter: Updates state from S1 to S2 using result T
- f: A ReaderIO Kleisli arrow (S1 -> ReaderIO[R, T])
func BindReaderIOKL ¶
func BindReaderIOKL[E, R, S, T any]( lens L.Lens[S, T], f readerio.Kleisli[R, T, T], ) Operator[R, E, S, S]
BindReaderIOKL is a lens-based variant of BindReaderIOK. It combines a lens with a ReaderIO Kleisli arrow, focusing on a specific field within the state structure.
Parameters:
- lens: A lens focusing on field T within state S
- f: A ReaderIO Kleisli arrow (T -> ReaderIO[R, T])
func BindReaderK ¶
func BindReaderK[E, R, S1, S2, T any]( setter func(T) func(S1) S2, f reader.Kleisli[R, S1, T], ) Operator[R, E, S1, S2]
BindReaderK is a variant of Bind that works with Reader computations. It lifts a Reader Kleisli arrow into the ReaderIOEither context.
Parameters:
- setter: Updates state from S1 to S2 using result T
- f: A Reader Kleisli arrow (S1 -> Reader[R, T])
func BindReaderKL ¶
func BindReaderKL[E, R, S, T any]( lens L.Lens[S, T], f reader.Kleisli[R, T, T], ) Operator[R, E, S, S]
BindReaderKL is a lens-based variant of BindReaderK. It combines a lens with a Reader Kleisli arrow, focusing on a specific field within the state structure.
Parameters:
- lens: A lens focusing on field T within state S
- f: A Reader Kleisli arrow (T -> Reader[R, T])
func BindTo ¶
func BindTo[R, E, S1, T any]( setter func(T) S1, ) Operator[R, E, T, S1]
BindTo initializes a new state [S1] from a value [T]
func Chain ¶
func Chain[R, E, A, B any](f Kleisli[R, E, A, B]) Operator[R, E, A, B]
Chain returns a function that sequences computations where the second depends on the first. This is the curried version of MonadChain.
func ChainConsumer ¶
func ChainConsumer[R, E, A any](c Consumer[A]) Operator[R, E, A, struct{}]
func ChainEitherK ¶
ChainEitherK returns a function that chains an Either-returning function into ReaderIOEither. This is the curried version of MonadChainEitherK.
func ChainFirst ¶
func ChainFirst[R, E, A, B any](f Kleisli[R, E, A, B]) Operator[R, E, A, A]
ChainFirst returns a function that sequences computations but keeps the first result. This is the curried version of MonadChainFirst.
func ChainFirstConsumer ¶
func ChainFirstConsumer[R, E, A any](c Consumer[A]) Operator[R, E, A, A]
func ChainFirstEitherK ¶
ChainFirstEitherK returns a function that chains an Either computation while preserving the original value. This is the curried version of MonadChainFirstEitherK.
func ChainFirstIOK ¶
ChainFirstIOK returns a function that chains an IO computation while preserving the original value. This is the curried version of MonadChainFirstIOK.
func ChainFirstLeft ¶
func ChainFirstLeft[A, R, EA, EB, B any](f Kleisli[R, EB, EA, B]) Operator[R, EA, A, A]
ChainFirstLeft is the curried version of MonadChainFirstLeft. It returns a function that chains a computation on the left (error) side while always preserving the original error.
This is particularly useful for adding error handling side effects (like logging, metrics, or notifications) in a functional pipeline. The original error is always returned regardless of what f returns (Left or Right), ensuring the error path is preserved.
Parameters:
- f: A function that takes an error of type EA and returns a ReaderIOEither (typically for side effects)
Returns:
- An Operator that performs the side effect but always returns the original error if input was Left
func ChainFirstReaderEitherK ¶
ChainReaderK returns a function that chains a Reader-returning function into ReaderIOEither. This is the curried version of MonadChainReaderK.
func ChainFirstReaderIOK ¶
func ChainFirstReaderK ¶
ChainReaderK returns a function that chains a Reader-returning function into ReaderIOEither. This is the curried version of MonadChainReaderK.
func ChainIOEitherK ¶
ChainIOEitherK returns a function that chains an IOEither-returning function into ReaderIOEither. This is the curried version of MonadChainIOEitherK.
func ChainIOK ¶
ChainIOK returns a function that chains an IO-returning function into ReaderIOEither. This is the curried version of MonadChainIOK.
func ChainReaderEitherK ¶
ChainReaderK returns a function that chains a Reader-returning function into ReaderIOEither. This is the curried version of MonadChainReaderK.
func ChainReaderIOK ¶
func ChainReaderK ¶
ChainReaderK returns a function that chains a Reader-returning function into ReaderIOEither. This is the curried version of MonadChainReaderK.
func Let ¶
func Let[R, E, S1, S2, T any]( setter func(T) func(S1) S2, f func(S1) T, ) Operator[R, E, S1, S2]
Let attaches the result of a computation to a context [S1] to produce a context [S2]
func LetL ¶
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 ReaderIOEither).
Example:
type State struct {
User User
Posts []Post
}
userLens := lens.MakeLens(
func(s State) User { return s.User },
func(s State, u User) State { s.User = u; return s },
)
result := F.Pipe2(
readerioeither.Do[any, error](State{User: User{Name: "Alice"}}),
readerioeither.LetL(userLens, func(user User) User {
user.Name = "Bob"
return user
}),
)
func LetTo ¶
func LetTo[R, E, S1, S2, T any]( setter func(T) func(S1) S2, b T, ) Operator[R, E, S1, S2]
LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetToL ¶
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
Posts []Post
}
userLens := lens.MakeLens(
func(s State) User { return s.User },
func(s State, u User) State { s.User = u; return s },
)
newUser := User{Name: "Bob", ID: 123}
result := F.Pipe2(
readerioeither.Do[any, error](State{}),
readerioeither.LetToL(userLens, newUser),
)
func Map ¶
func Map[R, E, A, B any](f func(A) B) Operator[R, E, A, B]
Map returns a function that applies a transformation to the success value of a ReaderIOEither. This is the curried version of MonadMap, useful for function composition.
func MapTo ¶
func MapTo[R, E, A, B any](b B) Operator[R, E, A, B]
MapTo returns a function that replaces the success value with a constant. This is the curried version of MonadMapTo.
func TapEitherK ¶
func TapReaderEitherK ¶
func TapReaderIOK ¶
func TapReaderK ¶
func WithLock ¶
func WithLock[R, E, A any](lock func() context.CancelFunc) Operator[R, E, A, A]
WithLock executes a ReaderIOEither operation within the scope of a lock. The lock is acquired before the operation executes and released after it completes, regardless of whether the operation succeeds or fails.
This is useful for ensuring thread-safe access to shared resources or for implementing critical sections in concurrent code.
Type parameters:
- R: The context type
- E: The error type
- A: The value type
Parameters:
- lock: A function that acquires a lock and returns a CancelFunc to release it
Returns:
An Operator that wraps the computation with lock acquisition and release
Example:
var mu sync.Mutex
safeFetch := F.Pipe1(
fetchData(),
WithLock[Config, error, Data](func() context.CancelFunc {
mu.Lock()
return func() { mu.Unlock() }
}),
)
type Reader ¶
Reader represents a computation that depends on some context/environment of type R and produces a value of type A. It's useful for dependency injection patterns.
type ReaderEither ¶
type ReaderEither[R, E, A any] = readereither.ReaderEither[R, E, A]
type ReaderIO ¶
ReaderIO represents a computation that depends on some context R and performs side effects to produce a value of type A.
type ReaderIOEither ¶
ReaderIOEither represents a computation that:
- Depends on some context/environment of type R (Reader)
- Performs side effects (IO)
- Can fail with an error of type E or succeed with a value of type A (Either)
It combines three powerful functional programming concepts:
- Reader monad for dependency injection
- IO monad for side effects
- Either monad for error handling
Type parameters:
- R: The type of the context/environment (e.g., configuration, dependencies)
- E: The type of errors that can occur
- A: The type of the success value
Example:
type Config struct { BaseURL string }
func fetchUser(id int) ReaderIOEither[Config, error, User] {
return func(cfg Config) IOEither[error, User] {
return func() Either[error, User] {
// Use cfg.BaseURL to fetch user
// Return either.Right(user) or either.Left(err)
}
}
}
func Ask ¶
func Ask[R, E any]() ReaderIOEither[R, E, R]
Ask returns a ReaderIOEither that retrieves the current context. Useful for accessing configuration or dependencies.
func Asks ¶
func Asks[E, R, A any](r Reader[R, A]) ReaderIOEither[R, E, A]
Asks returns a ReaderIOEither that retrieves a value derived from the context. This is useful for extracting specific fields from a configuration object.
func Bracket ¶
func Bracket[ R, E, A, B, ANY any]( acquire ReaderIOEither[R, E, A], use func(A) ReaderIOEither[R, E, B], release func(A, either.Either[E, B]) ReaderIOEither[R, E, ANY], ) ReaderIOEither[R, E, B]
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 Defer ¶
Defer creates a ReaderIOEither lazily via a generator function. The generator is called each time the ReaderIOEither is executed.
func Do ¶
func Do[R, E, S any]( empty S, ) ReaderIOEither[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
Posts []Post
}
type Env struct {
UserRepo UserRepository
PostRepo PostRepository
}
result := readerioeither.Do[Env, error](State{})
func Flatten ¶
func Flatten[R, E, A any](mma ReaderIOEither[R, E, ReaderIOEither[R, E, A]]) ReaderIOEither[R, E, A]
Flatten removes one level of nesting from a nested ReaderIOEither. Converts ReaderIOEither[R, E, ReaderIOEither[R, E, A]] to ReaderIOEither[R, E, A].
func FromEither ¶
FromEither lifts an Either into a ReaderIOEither context. The Either value is independent of any context or IO effects.
func FromIO ¶
func FromIO[R, E, A any](ma IO[A]) ReaderIOEither[R, E, A]
FromIO lifts an IO into a ReaderIOEither context. The IO result is placed in the Right side (success).
func FromIOEither ¶
func FromIOEither[R, E, A any](ma IOEither[E, A]) ReaderIOEither[R, E, A]
FromIOEither lifts an IOEither into a ReaderIOEither context. The computation becomes independent of any reader context.
func FromReader ¶
func FromReader[E, R, A any](ma Reader[R, A]) ReaderIOEither[R, E, A]
FromReader lifts a Reader into a ReaderIOEither context. The Reader result is placed in the Right side (success).
func FromReaderEither ¶
func FromReaderEither[R, E, A any](ma RE.ReaderEither[R, E, A]) ReaderIOEither[R, E, A]
FromReaderEither lifts a ReaderEither into a ReaderIOEither context. The Either result is lifted into an IO effect.
func FromReaderIO ¶
func FromReaderIO[E, R, A any](ma ReaderIO[R, A]) ReaderIOEither[R, E, A]
func Left ¶
func Left[R, A, E any](e E) ReaderIOEither[R, E, A]
Left creates a failed ReaderIOEither with the given error.
func LeftIO ¶
func LeftIO[R, A, E any](ma IO[E]) ReaderIOEither[R, E, A]
LeftIO lifts an IO into a ReaderIOEither, placing the result in the Left (error) side.
func LeftReader ¶
func LeftReader[A, R, E any](ma Reader[R, E]) ReaderIOEither[R, E, A]
LeftReader lifts a Reader into a ReaderIOEither, placing the result in the Left (error) side.
func LeftReaderIO ¶
func LeftReaderIO[A, R, E any](me ReaderIO[R, E]) ReaderIOEither[R, E, A]
LeftReaderIO lifts a ReaderIO into a ReaderIOEither, placing the result in the Left (error) side.
func Memoize ¶
func Memoize[ R, E, A any](rdr ReaderIOEither[R, E, A]) ReaderIOEither[R, E, A]
Memoize computes the value of the ReaderIOEither lazily but exactly once. The context used is from the first call. Do not use if the value depends on the context.
func MonadAlt ¶
func MonadAlt[R, E, A any](first ReaderIOEither[R, E, A], second L.Lazy[ReaderIOEither[R, E, A]]) ReaderIOEither[R, E, A]
MonadAlt tries the first computation, and if it fails, tries the second. This implements the Alternative pattern for error recovery.
func MonadAp ¶
func MonadAp[R, E, A, B any](fab ReaderIOEither[R, E, func(A) B], fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]
MonadAp applies a function wrapped in a context to a value wrapped in a context. Both computations are executed (default behavior may be sequential or parallel depending on implementation).
func MonadApPar ¶
func MonadApPar[R, E, A, B any](fab ReaderIOEither[R, E, func(A) B], fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]
MonadApPar applies a function in a context to a value in a context, executing them in parallel.
func MonadApSeq ¶
func MonadApSeq[R, E, A, B any](fab ReaderIOEither[R, E, func(A) B], fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]
MonadApSeq applies a function in a context to a value in a context, executing them sequentially.
func MonadBiMap ¶
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]
MonadBiMap applies two functions: one to the error, one to the success value. This allows transforming both channels simultaneously.
func MonadChain ¶
func MonadChain[R, E, A, B any](fa ReaderIOEither[R, E, A], f Kleisli[R, E, A, B]) ReaderIOEither[R, E, B]
MonadChain sequences two computations where the second depends on the result of the first. This is the fundamental operation for composing dependent effectful computations. If the first computation fails, the second is not executed.
func MonadChainEitherK ¶
func MonadChainEitherK[R, E, A, B any](ma ReaderIOEither[R, E, A], f either.Kleisli[E, A, B]) ReaderIOEither[R, E, B]
MonadChainEitherK chains a computation that returns an Either into a ReaderIOEither. The Either is automatically lifted into the ReaderIOEither context.
func MonadChainFirst ¶
func MonadChainFirst[R, E, A, B any](fa ReaderIOEither[R, E, A], f Kleisli[R, E, A, B]) ReaderIOEither[R, E, A]
MonadChainFirst sequences two computations but keeps the result of the first. Useful for performing side effects while preserving the original value.
func MonadChainFirstEitherK ¶
func MonadChainFirstEitherK[R, E, A, B any](ma ReaderIOEither[R, E, A], f either.Kleisli[E, A, B]) ReaderIOEither[R, E, A]
MonadChainFirstEitherK chains an Either-returning computation but keeps the original value. Useful for validation or side effects that return Either.
func MonadChainFirstIOK ¶
func MonadChainFirstIOK[R, E, A, B any](ma ReaderIOEither[R, E, A], f io.Kleisli[A, B]) ReaderIOEither[R, E, A]
MonadChainFirstIOK chains an IO computation but keeps the original value. Useful for performing IO side effects while preserving the original value.
func MonadChainFirstLeft ¶
func MonadChainFirstLeft[A, R, EA, EB, B any](ma ReaderIOEither[R, EA, A], f Kleisli[R, EB, EA, B]) ReaderIOEither[R, EA, A]
MonadChainFirstLeft chains a computation on the left (error) side but always returns the original error. If the input is a Left value, it applies the function f to the error and executes the resulting computation, but always returns the original Left error regardless of what f returns (Left or Right). If the input is a Right value, it passes through unchanged without calling f.
This is useful for side effects on errors (like logging or metrics) where you want to perform an action when an error occurs but always propagate the original error, ensuring the error path is preserved.
Parameters:
- ma: The input ReaderIOEither that may contain an error of type EA
- f: A function that takes an error of type EA and returns a ReaderIOEither (typically for side effects)
Returns:
- A ReaderIOEither with the original error preserved if input was Left, or the original Right value
func MonadChainFirstReaderK ¶
func MonadChainIOEitherK ¶
func MonadChainIOEitherK[R, E, A, B any](ma ReaderIOEither[R, E, A], f IOE.Kleisli[E, A, B]) ReaderIOEither[R, E, B]
MonadChainIOEitherK chains an IOEither-returning computation into a ReaderIOEither. The IOEither is automatically lifted into the ReaderIOEither context.
func MonadChainIOK ¶
func MonadChainIOK[R, E, A, B any](ma ReaderIOEither[R, E, A], f io.Kleisli[A, B]) ReaderIOEither[R, E, B]
MonadChainIOK chains an IO-returning computation into a ReaderIOEither. The IO is automatically lifted into the ReaderIOEither context (always succeeds).
func MonadChainLeft ¶
func MonadChainLeft[R, EA, EB, A any](fa ReaderIOEither[R, EA, A], f Kleisli[R, EB, EA, A]) ReaderIOEither[R, EB, A]
func MonadChainReaderEitherK ¶
func MonadChainReaderIOK ¶
func MonadChainReaderK ¶
func MonadChainReaderK[E, R, A, B any](ma ReaderIOEither[R, E, A], f reader.Kleisli[R, A, B]) ReaderIOEither[R, E, B]
MonadChainReaderK chains a Reader-returning computation into a ReaderIOEither. The Reader is automatically lifted into the ReaderIOEither context.
func MonadFlap ¶
func MonadFlap[R, E, B, A any](fab ReaderIOEither[R, E, func(A) B], a A) ReaderIOEither[R, E, B]
MonadFlap applies a value to a function wrapped in a context. This is the reverse of Ap - the value is fixed and the function varies.
func MonadMap ¶
func MonadMap[R, E, A, B any](fa ReaderIOEither[R, E, A], f func(A) B) ReaderIOEither[R, E, B]
MonadMap applies a function to the value inside a ReaderIOEither context. If the computation is successful (Right), the function is applied to the value. If it's an error (Left), the error is propagated unchanged.
func MonadMapLeft ¶
func MonadMapLeft[R, E1, E2, A any](fa ReaderIOEither[R, E1, A], f func(E1) E2) ReaderIOEither[R, E2, A]
MonadMapLeft applies a function to the error value, leaving success unchanged.
func MonadMapTo ¶
func MonadMapTo[R, E, A, B any](fa ReaderIOEither[R, E, A], b B) ReaderIOEither[R, E, B]
MonadMapTo replaces the success value with a constant value. Useful when you want to discard the result but keep the effect.
func MonadReduceArray ¶
func MonadReduceArray[R, E, A, B any](as []ReaderIOEither[R, E, A], reduce func(B, A) B, initial B) ReaderIOEither[R, E, B]
func MonadReduceArrayM ¶
func MonadTap ¶
func MonadTap[R, E, A, B any](fa ReaderIOEither[R, E, A], f Kleisli[R, E, A, B]) ReaderIOEither[R, E, A]
func MonadTapEitherK ¶
func MonadTapIOK ¶
func MonadTapLeft ¶
func MonadTapLeft[A, R, EA, EB, B any](ma ReaderIOEither[R, EA, A], f Kleisli[R, EB, EA, B]) ReaderIOEither[R, EA, A]
func MonadTapReaderEitherK ¶
func MonadTapReaderIOK ¶
func MonadTapReaderK ¶
func MonadTraverseReduceArray ¶
func MonadTraverseReduceArray[R, E, A, B, C any](as []A, trfrm Kleisli[R, E, A, B], reduce func(C, B) C, initial C) ReaderIOEither[R, E, C]
func Of ¶
func Of[R, E, A any](a A) ReaderIOEither[R, E, A]
Of creates a successful ReaderIOEither with the given value. This is the pointed functor operation, lifting a pure value into the ReaderIOEither context.
func Retrying ¶
func Retrying[R, E, A any]( policy retry.RetryPolicy, action Kleisli[R, E, retry.RetryStatus, A], check func(Either[E, A]) bool, ) ReaderIOEither[R, E, A]
func Right ¶
func Right[R, E, A any](a A) ReaderIOEither[R, E, A]
Right creates a successful ReaderIOEither with the given value.
func RightIO ¶
func RightIO[R, E, A any](ma IO[A]) ReaderIOEither[R, E, A]
RightIO lifts an IO into a ReaderIOEither, placing the result in the Right side.
func RightReader ¶
func RightReader[E, R, A any](ma Reader[R, A]) ReaderIOEither[R, E, A]
RightReader lifts a Reader into a ReaderIOEither, placing the result in the Right side.
func RightReaderIO ¶
func RightReaderIO[E, R, A any](ma ReaderIO[R, A]) ReaderIOEither[R, E, A]
RightReaderIO lifts a ReaderIO into a ReaderIOEither, placing the result in the Right side.
func SequenceArray ¶
func SequenceArray[R, E, A any](ma []ReaderIOEither[R, E, A]) ReaderIOEither[R, E, []A]
SequenceArray converts an array of ReaderIOEither into a ReaderIOEither 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:
- R: The context type
- E: The error type
- A: The element type
Parameters:
- ma: An array of ReaderIOEither computations
Returns:
A ReaderIOEither that produces an array of results
Example:
computations := []ReaderIOEither[Config, error, int]{
fetchCount("users"),
fetchCount("posts"),
fetchCount("comments"),
}
result := SequenceArray(computations)
// result(cfg)() returns Right([userCount, postCount, commentCount]) or Left(error)
Example ¶
Example of SequenceArray - execute multiple independent computations
package main
import (
"fmt"
E "github.com/IBM/fp-go/v2/either"
RIE "github.com/IBM/fp-go/v2/readerioeither"
)
type Config struct {
APIKey string
BaseURL string
}
func main() {
cfg := Config{APIKey: "secret"}
computations := []RIE.ReaderIOEither[Config, error, int]{
RIE.Of[Config, error](10),
RIE.Of[Config, error](20),
RIE.Of[Config, error](30),
}
result := RIE.SequenceArray(computations)(cfg)()
E.Fold(
func(err error) string {
fmt.Printf("Error: %v\n", err)
return ""
},
func(values []int) string {
sum := 0
for _, v := range values {
sum += v
}
fmt.Printf("Sum: %d\n", sum)
return ""
},
)(result)
}
Output: Sum: 60
func SequenceRecord ¶
func SequenceRecord[K comparable, R, E, A any](ma map[K]ReaderIOEither[R, E, A]) ReaderIOEither[R, E, map[K]A]
SequenceRecord converts a map of ReaderIOEither into a ReaderIOEither of a map.
This is useful when you have multiple independent computations keyed by some identifier and want to execute them all and collect their results. If any computation fails, the entire operation fails with the first error.
Type parameters:
- R: The context type
- K: The key type (must be comparable)
- E: The error type
- A: The value type
Parameters:
- ma: A map of ReaderIOEither computations
Returns:
A ReaderIOEither that produces a map of results
Example:
computations := map[string]ReaderIOEither[Config, error, int]{
"users": fetchCount("users"),
"posts": fetchCount("posts"),
}
result := SequenceRecord(computations)
// result(cfg)() returns Right(map[string]int{"users": 100, "posts": 50}) or Left(error)
func SequenceT1 ¶
SequenceT1 converts a single ReaderIOEither into a ReaderIOEither of a 1-tuple. This is useful for uniformly handling computations with different arities.
If the input computation fails, the result will be a Left with the error. If it succeeds, the result will be a Right with a tuple containing the value.
Example:
result := SequenceT1(Of[Config, error](42))
// result(cfg)() returns Right(Tuple1{42})
func SequenceT2 ¶
func SequenceT2[R, E, A, B any](a ReaderIOEither[R, E, A], b ReaderIOEither[R, E, B]) ReaderIOEither[R, E, T.Tuple2[A, B]]
SequenceT2 combines two ReaderIOEither computations into a single ReaderIOEither of a 2-tuple. Both computations are executed, and if both succeed, their results are combined into a tuple. If either fails, the result is a Left with the first error encountered.
This is useful for running multiple independent computations and collecting their results.
Example:
result := SequenceT2(
fetchUser(123),
fetchProfile(123),
)
// result(cfg)() returns Right(Tuple2{user, profile}) or Left(error)
func SequenceT3 ¶
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]]
SequenceT3 combines three ReaderIOEither computations into a single ReaderIOEither of a 3-tuple. All three computations are executed, and if all succeed, their results are combined into a tuple. If any fails, the result is a Left with the first error encountered.
Example:
result := SequenceT3(
fetchUser(123),
fetchProfile(123),
fetchSettings(123),
)
// result(cfg)() returns Right(Tuple3{user, profile, settings}) or Left(error)
func SequenceT4 ¶
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]]
SequenceT4 combines four ReaderIOEither computations into a single ReaderIOEither of a 4-tuple. All four computations are executed, and if all succeed, their results are combined into a tuple. If any fails, the result is a Left with the first error encountered.
Example:
result := SequenceT4(
fetchUser(123),
fetchProfile(123),
fetchSettings(123),
fetchPreferences(123),
)
// result(cfg)() returns Right(Tuple4{user, profile, settings, prefs}) or Left(error)
func Swap ¶
func Swap[R, E, A any](val ReaderIOEither[R, E, A]) ReaderIOEither[R, A, E]
Swap exchanges the error and success types. Left becomes Right and Right becomes Left.
func ThrowError ¶
func ThrowError[R, A, E any](e E) ReaderIOEither[R, E, A]
ThrowError creates a failed ReaderIOEither with the given error. This is an alias for Left, following the naming convention from other functional libraries.
type ReaderOption ¶
type ReaderOption[R, A any] = readeroption.ReaderOption[R, A]