readerreaderioeither

package
v2.2.23 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 25, 2026 License: Apache-2.0 Imports: 26 Imported by: 0

Documentation

Overview

Package readerreaderioeither provides a functional programming abstraction that combines four powerful concepts: Reader, Reader, IO, and Either monads in a nested structure.

Type Parameter Ordering Convention

This package follows a consistent convention for ordering type parameters in function signatures. The general rule is: R -> C -> E -> T (outer context, inner context, error, type), where:

  • R: The outer Reader context/environment type
  • C: The inner Reader context/environment type (for the ReaderIOEither)
  • E: The Either error type
  • T: The value type(s) (A, B, etc.)

However, when some type parameters can be automatically inferred by the Go compiler from function arguments, the convention is modified to minimize explicit type annotations:

Rule: Undetectable types come first, followed by detectable types, while preserving the relative order within each group (R -> C -> E -> T).

Examples:

  1. All types detectable from first argument: MonadMap[R, C, E, A, B](fa ReaderReaderIOEither[R, C, E, A], f func(A) B) - R, C, E, A are detectable from fa - B is detectable from f - Order: R, C, E, A, B (standard order, all detectable)

  2. Some types undetectable: FromReader[C, E, R, A](ma Reader[R, A]) ReaderReaderIOEither[R, C, E, A] - R, A are detectable from ma - C, E are undetectable (not in any argument) - Order: C, E, R, A (C, E first as undetectable, then R, A in standard order)

  3. Multiple undetectable types: Local[C, E, A, R1, R2](f func(R2) R1) func(ReaderReaderIOEither[R1, C, E, A]) ReaderReaderIOEither[R2, C, E, A] - C, E, A are undetectable - R1, R2 are detectable from f - Order: C, E, A, R1, R2 (undetectable first, then detectable)

  4. Functions returning Kleisli arrows: ChainReaderOptionK[R, C, A, B, E](onNone Lazy[E]) func(readeroption.Kleisli[R, A, B]) Operator[R, C, E, A, B] - Canonical order would be R, C, E, A, B - E is detectable from onNone parameter - R, C, A, B are not detectable (they're in the Kleisli argument type) - Order: R, C, A, B, E (undetectable R, C, A, B first, then detectable E)

This convention allows for more ergonomic function calls:

// Without convention - need to specify all types:
result := FromReader[OuterCtx, InnerCtx, error, User](readerFunc)

// With convention - only specify undetectable types:
result := FromReader[InnerCtx, error](readerFunc)  // R and A inferred from readerFunc

The reasoning behind this approach is to reduce the number of explicit type parameters that developers need to specify when calling functions, improving code readability and reducing verbosity while maintaining type safety.

Additional examples demonstrating the convention:

  1. FromReaderOption[R, C, A, E](onNone Lazy[E]) Kleisli[R, C, E, ReaderOption[R, A], A] - Canonical order would be R, C, E, A - E is detectable from onNone parameter - R, C, A are not detectable (they're in the return type's Kleisli) - Order: R, C, A, E (undetectable R, C, A first, then detectable E)

  2. MapLeft[R, C, A, E1, E2](f func(E1) E2) func(ReaderReaderIOEither[R, C, E1, A]) ReaderReaderIOEither[R, C, E2, A] - Canonical order would be R, C, E1, E2, A - E1, E2 are detectable from f parameter - R, C, A are not detectable (they're in the return type) - Order: R, C, A, E1, E2 (undetectable R, C, A first, then detectable E1, E2)

Additional special cases:

  • Ap[B, R, C, E, A]: B is undetectable (in function return type), so B comes first
  • ChainOptionK[R, C, A, B, E]: R, C, A, B are undetectable, E is detectable from onNone
  • FromReaderIO[C, E, R, A]: C, E are undetectable, R, A are detectable from ReaderIO[R, A]

All functions in this package follow this convention consistently.

Fantasy Land Specification

This is a monad transformer combining:

Implemented Fantasy Land algebras:

ReaderReaderIOEither

ReaderReaderIOEither[R, C, E, A] represents a computation that:

  • Depends on an outer context/environment of type R (outer Reader)
  • Returns a computation that depends on an inner context/environment of type C (inner 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:

  • Multi-level dependency injection patterns
  • Layered architectures with different context requirements at each layer
  • Composing operations that need access to multiple levels of configuration or context
  • Building reusable components that can be configured at different stages

Core Operations

Construction:

  • Of/Right: Create a successful computation
  • Left: Create a failed computation
  • FromEither: Lift an Either into ReaderReaderIOEither
  • FromIO: Lift an IO into ReaderReaderIOEither
  • FromReader: Lift a Reader into ReaderReaderIOEither
  • FromReaderIO: Lift a ReaderIO into ReaderReaderIOEither
  • FromIOEither: Lift an IOEither into ReaderReaderIOEither
  • FromReaderEither: Lift a ReaderEither into ReaderReaderIOEither
  • FromReaderIOEither: Lift a ReaderIOEither into ReaderReaderIOEither
  • FromReaderOption: Lift a ReaderOption into ReaderReaderIOEither

Transformation:

  • Map: Transform the success value
  • MapLeft: Transform the error value
  • Chain/Bind: Sequence dependent computations
  • Flatten: Flatten nested ReaderReaderIOEither

Combination:

  • Ap: Apply a function in a context to a value in a context
  • ApSeq: Sequential application
  • ApPar: Parallel application

Error Handling:

  • Alt: Choose the first successful computation

Context Access:

  • Ask: Get the current outer context
  • Asks: Get a value derived from the outer context
  • Local: Run a computation with a modified outer context
  • Read: Execute with a specific outer context

Kleisli Composition:

  • ChainEitherK: Chain with Either-returning functions
  • ChainReaderK: Chain with Reader-returning functions
  • ChainReaderIOK: Chain with ReaderIO-returning functions
  • ChainReaderEitherK: Chain with ReaderEither-returning functions
  • ChainReaderOptionK: Chain with ReaderOption-returning functions
  • ChainIOEitherK: Chain with IOEither-returning functions
  • ChainIOK: Chain with IO-returning functions
  • ChainOptionK: Chain with Option-returning functions

First/Tap Operations (execute for side effects, return original value):

  • ChainFirst/Tap: Execute a computation but return the original value
  • ChainFirstEitherK/TapEitherK: Tap with Either-returning functions
  • ChainFirstReaderK/TapReaderK: Tap with Reader-returning functions
  • ChainFirstReaderIOK/TapReaderIOK: Tap with ReaderIO-returning functions
  • ChainFirstReaderEitherK/TapReaderEitherK: Tap with ReaderEither-returning functions
  • ChainFirstReaderOptionK/TapReaderOptionK: Tap with ReaderOption-returning functions
  • ChainFirstIOK/TapIOK: Tap with IO-returning functions

Example Usage

type OuterConfig struct {
    DatabaseURL string
    LogLevel    string
}

type InnerConfig struct {
    APIKey  string
    Timeout time.Duration
}

// A computation that depends on both OuterConfig and InnerConfig
func fetchUser(id int) readerreaderioeither.ReaderReaderIOEither[OuterConfig, InnerConfig, error, User] {
    return func(outerCfg OuterConfig) readerioeither.ReaderIOEither[InnerConfig, error, User] {
        // Use outerCfg.DatabaseURL and outerCfg.LogLevel
        return func(innerCfg InnerConfig) ioeither.IOEither[error, User] {
            // Use innerCfg.APIKey and innerCfg.Timeout to fetch user
            return func() either.Either[error, User] {
                // Perform the actual IO operation
                // Return either.Right(user) or either.Left(err)
            }
        }
    }
}

// Compose operations
result := function.Pipe2(
    fetchUser(123),
    readerreaderioeither.Map[OuterConfig, InnerConfig, error](func(u User) string { return u.Name }),
    readerreaderioeither.Chain[OuterConfig, InnerConfig, error](func(name string) readerreaderioeither.ReaderReaderIOEither[OuterConfig, InnerConfig, error, string] {
        return readerreaderioeither.Of[OuterConfig, InnerConfig, error]("Hello, " + name)
    }),
)

// Execute with both configs
outerConfig := OuterConfig{DatabaseURL: "postgres://...", LogLevel: "info"}
innerConfig := InnerConfig{APIKey: "secret", Timeout: 30 * time.Second}
outcome := result(outerConfig)(innerConfig)() // 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

Constants

This section is empty.

Variables

This section is empty.

Functions

func ChainFirstReaderOptionK

func ChainFirstReaderOptionK[R, C, A, B, E any](onNone Lazy[E]) func(readeroption.Kleisli[R, A, B]) Operator[R, C, E, A, A]

ChainFirstReaderOptionK chains a ReaderOption computation while preserving the original value. If the ReaderOption is None, the provided error function is called.

func ChainLeft

func ChainLeft[R, C, EA, EB, A any](f Kleisli[R, C, EB, EA, A]) func(ReaderReaderIOEither[R, C, EA, A]) ReaderReaderIOEither[R, C, EB, A]

ChainLeft returns a function that chains a computation on the error channel. This is the curried version of MonadChainLeft.

func ChainOptionK

func ChainOptionK[R, C, A, B, E any](onNone Lazy[E]) func(option.Kleisli[A, B]) Operator[R, C, E, A, B]

ChainOptionK returns a function that chains an Option-returning function into ReaderReaderIOEither. If the Option is None, the provided error function is called.

func ChainReaderOptionK

func ChainReaderOptionK[R, C, A, B, E any](onNone Lazy[E]) func(readeroption.Kleisli[R, A, B]) Operator[R, C, E, A, B]

ChainReaderOptionK returns a function that chains a ReaderOption-returning function into ReaderReaderIOEither. If the ReaderOption is None, the provided error function is called.

func FromOption

func FromOption[R, C, A, E any](onNone Lazy[E]) func(Option[A]) ReaderReaderIOEither[R, C, E, A]

FromOption converts an Option to a ReaderReaderIOEither. If the Option is None, the provided function is called to produce the error.

func FromPredicate

func FromPredicate[R, C, E, A any](pred func(A) bool, onFalse func(A) E) func(A) ReaderReaderIOEither[R, C, E, A]

FromPredicate creates a ReaderReaderIOEither from a predicate. If the predicate returns false, the onFalse function is called to produce the error.

func Local

func Local[C, E, A, R1, R2 any](f func(R2) R1) func(ReaderReaderIOEither[R1, C, E, A]) ReaderReaderIOEither[R2, C, E, A]

func LocalEitherK added in v2.2.1

func LocalEitherK[C, A, R1, R2, E any](f either.Kleisli[E, R2, R1]) func(ReaderReaderIOEither[R1, C, E, A]) ReaderReaderIOEither[R2, C, E, A]

func LocalIOEitherK added in v2.2.1

func LocalIOEitherK[C, A, R1, R2, E any](f ioeither.Kleisli[E, R2, R1]) func(ReaderReaderIOEither[R1, C, E, A]) ReaderReaderIOEither[R2, C, E, A]

func LocalIOK added in v2.2.1

func LocalIOK[C, E, A, R1, R2 any](f io.Kleisli[R2, R1]) func(ReaderReaderIOEither[R1, C, E, A]) ReaderReaderIOEither[R2, C, E, A]

func LocalReaderIOEitherK added in v2.2.1

func LocalReaderIOEitherK[A, C, E, R1, R2 any](f readerioeither.Kleisli[C, E, R2, R1]) func(ReaderReaderIOEither[R1, C, E, A]) ReaderReaderIOEither[R2, C, E, A]

func LocalReaderReaderIOEitherK added in v2.2.1

func LocalReaderReaderIOEitherK[A, C, E, R1, R2 any](f Kleisli[R2, C, E, R2, R1]) func(ReaderReaderIOEither[R1, C, E, A]) ReaderReaderIOEither[R2, C, E, A]

func MapLeft

func MapLeft[R, C, A, E1, E2 any](f func(E1) E2) func(ReaderReaderIOEither[R, C, E1, A]) ReaderReaderIOEither[R, C, E2, A]

MapLeft returns a function that transforms the error channel. This is the curried version of MonadMapLeft.

func Read

func Read[C, E, A, R any](r R) func(ReaderReaderIOEither[R, C, E, A]) ReaderIOEither[C, E, A]

Read executes a ReaderReaderIOEither by providing a concrete outer environment value.

func ReadIO

func ReadIO[C, E, A, R any](rio IO[R]) func(ReaderReaderIOEither[R, C, E, A]) ReaderIOEither[C, E, A]

ReadIO executes a ReaderReaderIOEither by providing an outer environment obtained from an IO.

func ReadIOEither

func ReadIOEither[A, R, C, E any](rio IOEither[E, R]) func(ReaderReaderIOEither[R, C, E, A]) ReaderIOEither[C, E, A]

ReadIOEither executes a ReaderReaderIOEither by providing an outer environment obtained from an IOEither.

func TapReaderOptionK

func TapReaderOptionK[R, C, A, B, E any](onNone Lazy[E]) func(readeroption.Kleisli[R, A, B]) Operator[R, C, E, A, A]

TapReaderOptionK is an alias for ChainFirstReaderOptionK, executing a ReaderOption side effect while preserving the original value.

func Traverse added in v2.1.17

func Traverse[R2, R1, C, E, A, B any](
	f Kleisli[R1, C, E, A, B],
) func(ReaderReaderIOEither[R2, C, E, A]) Kleisli[R2, C, E, R1, B]

Traverse transforms a ReaderReaderIOEither computation by applying a function that produces another ReaderReaderIOEither, effectively swapping the order of outer 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 R1 first, then R2, and produces a ReaderIOEither[C, E, B].

Type Parameters:

  • R2: The outer environment type from the original computation
  • R1: The inner environment type introduced by the transformation
  • C: The inner context/environment type (for the ReaderIOEither layer)
  • E: The error type
  • A: The input value type
  • B: The output value type

Parameters:

  • f: A Kleisli arrow that transforms A into a ReaderReaderIOEither[R1, C, E, B]

Returns:

  • A function that takes a ReaderReaderIOEither[R2, C, E, A] and returns a Kleisli[R2, C, E, R1, B], which is func(R1) ReaderReaderIOEither[R2, C, E, B]

The function preserves error handling and IO effects while reordering the environment dependencies. This is the generalized version of Sequence that also applies a transformation function.

Example:

type UserConfig struct {
    UserID int
}
type SystemConfig struct {
    SystemID string
}
type Context struct {
    RequestID string
}

// Original computation depending on SystemConfig
original := readerreaderioeither.Of[SystemConfig, Context, error](42)

// Transformation that introduces UserConfig dependency
transform := func(n int) readerreaderioeither.ReaderReaderIOEither[UserConfig, Context, error, string] {
    return func(userCfg UserConfig) readerioeither.ReaderIOEither[Context, error, string] {
        return readerioeither.Of[Context, error](fmt.Sprintf("User %d: %d", userCfg.UserID, n))
    }
}

// Apply traverse to swap order and transform
traversed := Traverse[SystemConfig, UserConfig, Context, error, int, string](transform)(original)

// Provide UserConfig first, then SystemConfig
result := traversed(UserConfig{UserID: 1})(SystemConfig{SystemID: "sys1"})(Context{RequestID: "req1"})()

func TraverseReader added in v2.1.17

func TraverseReader[R2, R1, C, E, A, B any](
	f reader.Kleisli[R1, A, B],
) func(ReaderReaderIOEither[R2, C, E, A]) Kleisli[R2, C, E, R1, B]

TraverseReader transforms a ReaderReaderIOEither 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 ReaderReaderIOEither. The result allows you to provide the Reader's environment (R1) first, which then produces a ReaderReaderIOEither that depends on environment R2.

Type Parameters:

  • R2: The outer environment type from the original ReaderReaderIOEither
  • R1: The inner environment type introduced by the Reader transformation
  • C: The inner context/environment type (for the ReaderIOEither layer)
  • 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 ReaderReaderIOEither[R2, C, E, A] and returns a Kleisli[R2, C, E, R1, B], which is func(R1) ReaderReaderIOEither[R2, C, E, B]

The function preserves error handling and IO effects while adding the Reader environment dependency and reordering the environment parameters. This is useful when you want to introduce a pure (non-IO, non-error) environment dependency to an existing computation.

Example:

type SystemConfig struct {
    Timeout int
}
type UserPreferences struct {
    Theme string
}
type Context struct {
    SessionID string
}

// Original computation depending on SystemConfig
original := readerreaderioeither.Of[SystemConfig, Context, error](100)

// Pure Reader transformation that introduces UserPreferences dependency
formatWithTheme := func(value int) reader.Reader[UserPreferences, string] {
    return func(prefs UserPreferences) string {
        return fmt.Sprintf("[%s theme] Value: %d", prefs.Theme, value)
    }
}

// Apply traverse to introduce UserPreferences and swap order
traversed := TraverseReader[SystemConfig, UserPreferences, Context, error, int, string](formatWithTheme)(original)

// Provide UserPreferences first, then SystemConfig
result := traversed(UserPreferences{Theme: "dark"})(SystemConfig{Timeout: 30})(Context{SessionID: "sess1"})()

Types

type Either

type Either[E, A any] = either.Either[E, A]

Either represents a value that is either a Left (error) E or a Right (success) A. It's an alias for either.Either[E, A].

type IO

type IO[A any] = io.IO[A]

IO represents a side-effecting computation that produces a value A. It's an alias for io.IO[A].

type IOEither

type IOEither[E, A any] = ioeither.IOEither[E, A]

IOEither represents a side-effecting computation that produces either an error E or a value A. It's an alias for ioeither.IOEither[E, A].

type Kleisli

type Kleisli[R, C, E, A, B any] = Reader[A, ReaderReaderIOEither[R, C, E, B]]

Kleisli represents a Kleisli arrow for ReaderReaderIOEither. It's a function that takes a value A and returns a ReaderReaderIOEither[R, C, E, B].

Kleisli arrows are used for monadic composition, allowing you to chain computations that depend on two environments, perform side effects, and may fail.

Type Parameters:

  • R: The outer environment type
  • C: The inner environment type
  • E: The error type
  • A: The input value type
  • B: The output value type

Example:

// A Kleisli arrow that validates and processes a user ID
validateUser := func(userID int) ReaderReaderIOEither[Config, Context, error, User] {
    return func(cfg Config) readerioeither.ReaderIOEither[Context, error, User] {
        return func(ctx Context) ioeither.IOEither[error, User] {
            return func() either.Either[error, User] {
                if userID <= 0 {
                    return either.Left[User](errors.New("invalid user ID"))
                }
                return either.Right[error](User{ID: userID})
            }
        }
    }
}

func FromReaderOption

func FromReaderOption[R, C, A, E any](onNone Lazy[E]) Kleisli[R, C, E, ReaderOption[R, A], A]

FromReaderOption converts a ReaderOption to a ReaderReaderIOEither. If the ReaderOption is None, the provided function is called to produce the error.

func Sequence added in v2.1.17

func Sequence[R1, R2, C, E, A any](ma ReaderReaderIOEither[R2, C, E, ReaderReaderIOEither[R1, C, E, A]]) Kleisli[R2, C, E, R1, A]

Sequence swaps the order of nested environment parameters in a ReaderReaderIOEither computation.

This function takes a ReaderReaderIOEither that produces another ReaderReaderIOEither and returns a Kleisli arrow that reverses the order of the outer environment parameters (R1 and R2). The result is a curried function that takes R1 first, then R2, and produces a ReaderIOEither[C, E, A].

Type Parameters:

  • R1: The first outer environment type (becomes the outermost after sequence)
  • R2: The second outer environment type (becomes inner after sequence)
  • C: The inner context/environment type (for the ReaderIOEither layer)
  • E: The error type
  • A: The success value type

Parameters:

  • ma: A ReaderReaderIOEither[R2, C, E, ReaderReaderIOEither[R1, C, E, A]]

Returns:

  • A Kleisli[R2, C, E, R1, A], which is func(R1) ReaderReaderIOEither[R2, C, E, A]

The function preserves error handling and IO effects at all levels while reordering the outer environment dependencies. This is particularly useful when you need to change the order in which contexts are provided to a nested computation.

Example:

type OuterConfig struct {
    DatabaseURL string
}
type InnerConfig struct {
    APIKey string
}
type RequestContext struct {
    UserID int
}

// Original: takes OuterConfig, returns computation that may produce
// another computation depending on InnerConfig
original := func(outer OuterConfig) readerioeither.ReaderIOEither[RequestContext, error,
    readerreaderioeither.ReaderReaderIOEither[InnerConfig, RequestContext, error, string]] {
    return readerioeither.Of[RequestContext, error](
        readerreaderioeither.Of[InnerConfig, RequestContext, error]("result"),
    )
}

// Sequence swaps InnerConfig and OuterConfig order
sequenced := Sequence(original)

// Now provide InnerConfig first, then OuterConfig
result := sequenced(InnerConfig{APIKey: "key"})(OuterConfig{DatabaseURL: "db"})(RequestContext{UserID: 1})()

func SequenceReader added in v2.1.17

func SequenceReader[R1, R2, C, E, A any](ma ReaderReaderIOEither[R2, C, E, Reader[R1, A]]) Kleisli[R2, C, 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 ReaderReaderIOEither. It takes a ReaderReaderIOEither that produces a Reader and returns a Kleisli arrow that reverses the order of the outer environment parameters.

Type Parameters:

  • R1: The first environment type (becomes outermost after sequence)
  • R2: The second environment type (becomes inner after sequence)
  • C: The inner context/environment type (for the ReaderIOEither layer)
  • E: The error type (only present in the ReaderReaderIOEither layer)
  • A: The success value type

Parameters:

  • ma: A ReaderReaderIOEither[R2, C, E, Reader[R1, A]]

Returns:

  • A Kleisli[R2, C, E, R1, A], which is func(R1) ReaderReaderIOEither[R2, C, E, A]

The function lifts the pure Reader computation into the ReaderIOEither context while reordering the environment dependencies.

Example:

type Config struct {
    Multiplier int
}
type Database struct {
    ConnectionString string
}
type Context struct {
    RequestID string
}

// Original: takes Config, may produce a Reader[Database, int]
original := func(cfg Config) readerioeither.ReaderIOEither[Context, error, reader.Reader[Database, int]] {
    return readerioeither.Of[Context, error](func(db Database) int {
        return len(db.ConnectionString) * cfg.Multiplier
    })
}

// Sequence to provide Database first, then Config
sequenced := SequenceReader(original)
result := sequenced(Database{ConnectionString: "localhost"})(Config{Multiplier: 2})(Context{RequestID: "123"})()

func SequenceReaderIO added in v2.1.17

func SequenceReaderIO[R1, R2, C, E, A any](ma ReaderReaderIOEither[R2, C, E, ReaderIO[R1, A]]) Kleisli[R2, C, 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 ReaderReaderIOEither. It takes a ReaderReaderIOEither that produces a ReaderIO and returns a Kleisli arrow that reverses the order of the outer environment parameters.

Type Parameters:

  • R1: The first environment type (becomes outermost after sequence)
  • R2: The second environment type (becomes inner after sequence)
  • C: The inner context/environment type (for the ReaderIOEither layer)
  • E: The error type (only present in the outer ReaderReaderIOEither layer)
  • A: The success value type

Parameters:

  • ma: A ReaderReaderIOEither[R2, C, E, ReaderIO[R1, A]]

Returns:

  • A Kleisli[R2, C, E, R1, A], which is func(R1) ReaderReaderIOEither[R2, C, E, A]

The function lifts the ReaderIO computation (which has IO effects but no error handling) into the ReaderIOEither context while reordering the environment dependencies.

Example:

type Config struct {
    FilePath string
}
type Logger struct {
    Level string
}
type Context struct {
    TraceID string
}

// Original: takes Config, may produce a ReaderIO[Logger, string]
original := func(cfg Config) readerioeither.ReaderIOEither[Context, error, readerio.ReaderIO[Logger, string]] {
    return readerioeither.Of[Context, error](func(logger Logger) io.IO[string] {
        return func() string {
            return fmt.Sprintf("[%s] Reading from %s", logger.Level, cfg.FilePath)
        }
    })
}

// Sequence to provide Logger first, then Config
sequenced := SequenceReaderIO(original)
result := sequenced(Logger{Level: "INFO"})(Config{FilePath: "/data"})(Context{TraceID: "abc"})()

func TraverseArray added in v2.2.1

func TraverseArray[R, C, E, A, B any](f Kleisli[R, C, E, A, B]) Kleisli[R, C, E, []A, []B]

type Lazy

type Lazy[A any] = lazy.Lazy[A]

Lazy represents a lazily evaluated computation that produces a value of type A. It's an alias for lazy.Lazy[A].

type Lens

type Lens[S, T any] = lens.Lens[S, T]

Lens represents an optic for focusing on a part of a data structure. It's an alias for lens.Lens[S, T].

type Monoid

type Monoid[R, C, E, A any] = monoid.Monoid[ReaderReaderIOEither[R, C, E, A]]

func AltMonoid

func AltMonoid[R, C, E, A any](zero Lazy[ReaderReaderIOEither[R, C, E, A]]) Monoid[R, C, E, A]

func AlternativeMonoid

func AlternativeMonoid[R, C, E, A any](m monoid.Monoid[A]) Monoid[R, C, E, A]

func ApplicativeMonoid

func ApplicativeMonoid[R, C, E, A any](m monoid.Monoid[A]) Monoid[R, C, E, A]

func ApplicativeMonoidPar

func ApplicativeMonoidPar[R, C, E, A any](m monoid.Monoid[A]) Monoid[R, C, E, A]

func ApplicativeMonoidSeq

func ApplicativeMonoidSeq[R, C, E, A any](m monoid.Monoid[A]) Monoid[R, C, E, A]

type Operator

type Operator[R, C, E, A, B any] = Kleisli[R, C, E, ReaderReaderIOEither[R, C, E, A], B]

Operator represents an endomorphism in the Kleisli category for ReaderReaderIOEither. It's a Kleisli arrow where the input is itself a ReaderReaderIOEither[R, C, E, A].

Operators are useful for transforming or enhancing existing computations, such as adding logging, retry logic, or resource management.

Type Parameters:

  • R: The outer environment type
  • C: The inner environment type
  • E: The error type
  • A: The input computation's value type
  • B: The output value type

Example:

// An operator that adds retry logic to a computation
withRetry := func(computation ReaderReaderIOEither[Config, Context, error, int]) ReaderReaderIOEither[Config, Context, error, int] {
    return func(cfg Config) readerioeither.ReaderIOEither[Context, error, int] {
        return func(ctx Context) ioeither.IOEither[error, int] {
            return func() either.Either[error, int] {
                // Retry logic here
                return computation(cfg)(ctx)()
            }
        }
    }
}

func After

func After[R, C, E, A any](timestamp time.Time) Operator[R, C, E, A, A]

After creates an operation that passes after the given time.Time.

func Alt

func Alt[R, C, E, A any](second Lazy[ReaderReaderIOEither[R, C, E, A]]) Operator[R, C, E, A, A]

Alt returns a function that tries an alternative computation if the first fails. This is the curried version of MonadAlt.

func Ap

func Ap[B, R, C, E, A any](fa ReaderReaderIOEither[R, C, E, A]) Operator[R, C, E, func(A) B, 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 ApEitherS

func ApEitherS[R, C, E, S1, S2, T any](
	setter func(T) func(S1) S2,
	fa Either[E, T],
) Operator[R, C, E, S1, S2]

ApEitherS applies an Either computation and attaches its result to the context.

func ApEitherSL

func ApEitherSL[R, C, E, S, T any](
	lens Lens[S, T],
	fa Either[E, T],
) Operator[R, C, E, S, S]

ApEitherSL is a lens-based version of ApEitherS.

func ApIOEitherS

func ApIOEitherS[R, C, E, S1, S2, T any](
	setter func(T) func(S1) S2,
	fa IOEither[E, T],
) Operator[R, C, E, S1, S2]

ApIOEitherS applies an IOEither computation and attaches its result to the context.

func ApIOEitherSL

func ApIOEitherSL[R, C, E, S, T any](
	lens Lens[S, T],
	fa IOEither[E, T],
) Operator[R, C, E, S, S]

ApIOEitherSL is a lens-based version of ApIOEitherS.

func ApIOS

func ApIOS[R, C, E, S1, S2, T any](
	setter func(T) func(S1) S2,
	fa IO[T],
) Operator[R, C, E, S1, S2]

ApIOS applies an IO computation and attaches its result to the context.

func ApIOSL

func ApIOSL[R, C, E, S, T any](
	lens Lens[S, T],
	fa IO[T],
) Operator[R, C, E, S, S]

ApIOSL is a lens-based version of ApIOS.

func ApReaderIOS

func ApReaderIOS[C, E, R, S1, S2, T any](
	setter func(T) func(S1) S2,
	fa ReaderIO[R, T],
) Operator[R, C, E, S1, S2]

ApReaderIOS applies a ReaderIO computation and attaches its result to the context.

func ApReaderIOSL

func ApReaderIOSL[C, E, R, S, T any](
	lens Lens[S, T],
	fa ReaderIO[R, T],
) Operator[R, C, E, S, S]

ApReaderIOSL is a lens-based version of ApReaderIOS.

func ApReaderS

func ApReaderS[C, E, R, S1, S2, T any](
	setter func(T) func(S1) S2,
	fa Reader[R, T],
) Operator[R, C, E, S1, S2]

ApReaderS applies a Reader computation and attaches its result to the context.

func ApReaderSL

func ApReaderSL[C, E, R, S, T any](
	lens Lens[S, T],
	fa Reader[R, T],
) Operator[R, C, E, S, S]

ApReaderSL is a lens-based version of ApReaderS.

func ApS

func ApS[R, C, E, S1, S2, T any](
	setter func(T) func(S1) S2,
	fa ReaderReaderIOEither[R, C, E, T],
) Operator[R, C, E, S1, S2]

ApS applies a computation in parallel (applicative style) and attaches its result to the context. Unlike Bind, this doesn't allow the computation to depend on the current context state.

Example:

readerreaderioeither.ApS(
    func(count int) func(State) State {
        return func(s State) State { s.Count = count; return s }
    },
    getCount, // ReaderReaderIOEither[OuterEnv, InnerEnv, error, int]
)

func ApSL

func ApSL[R, C, E, S, T any](
	lens Lens[S, T],
	fa ReaderReaderIOEither[R, C, E, T],
) Operator[R, C, E, S, S]

ApSL is a lens-based version of ApS that uses a lens to focus on a specific field in the context.

func Bind

func Bind[R, C, E, S1, S2, T any](
	setter func(T) func(S1) S2,
	f func(S1) ReaderReaderIOEither[R, C, E, T],
) Operator[R, C, 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 both the outer (R) and inner (C) reader environments.

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 OuterEnv struct {
    Database string
}
type InnerEnv struct {
    UserRepo UserRepository
    PostRepo PostRepository
}

result := F.Pipe2(
    readerreaderioeither.Do[OuterEnv, InnerEnv, error](State{}),
    readerreaderioeither.Bind(
        func(user User) func(State) State {
            return func(s State) State { s.User = user; return s }
        },
        func(s State) readerreaderioeither.ReaderReaderIOEither[OuterEnv, InnerEnv, error, User] {
            return func(outer OuterEnv) readerioeither.ReaderIOEither[InnerEnv, error, User] {
                return readerioeither.Asks(func(inner InnerEnv) ioeither.IOEither[error, User] {
                    return inner.UserRepo.FindUser(outer.Database)
                })
            }
        },
    ),
    readerreaderioeither.Bind(
        func(posts []Post) func(State) State {
            return func(s State) State { s.Posts = posts; return s }
        },
        func(s State) readerreaderioeither.ReaderReaderIOEither[OuterEnv, InnerEnv, error, []Post] {
            return func(outer OuterEnv) readerioeither.ReaderIOEither[InnerEnv, error, []Post] {
                return readerioeither.Asks(func(inner InnerEnv) ioeither.IOEither[error, []Post] {
                    return inner.PostRepo.FindPostsByUser(outer.Database, s.User.ID)
                })
            }
        },
    ),
)

func BindEitherK

func BindEitherK[R, C, E, S1, S2, T any](
	setter func(T) func(S1) S2,
	f either.Kleisli[E, S1, T],
) Operator[R, C, E, S1, S2]

BindEitherK binds a computation that returns an Either to the context. The Kleisli function is automatically lifted into ReaderReaderIOEither.

func BindIOEitherK

func BindIOEitherK[R, C, E, S1, S2, T any](
	setter func(T) func(S1) S2,
	f ioeither.Kleisli[E, S1, T],
) Operator[R, C, E, S1, S2]

BindIOEitherK binds a computation that returns an IOEither to the context. The Kleisli function is automatically lifted into ReaderReaderIOEither.

func BindIOEitherKL

func BindIOEitherKL[R, C, E, S, T any](
	lens Lens[S, T],
	f ioeither.Kleisli[E, T, T],
) Operator[R, C, E, S, S]

BindIOEitherKL is a lens-based version of BindIOEitherK.

func BindIOK

func BindIOK[R, C, E, S1, S2, T any](
	setter func(T) func(S1) S2,
	f io.Kleisli[S1, T],
) Operator[R, C, E, S1, S2]

BindIOK binds a computation that returns an IO to the context. The Kleisli function is automatically lifted into ReaderReaderIOEither.

func BindIOKL

func BindIOKL[R, C, E, S, T any](
	lens Lens[S, T],
	f io.Kleisli[T, T],
) Operator[R, C, E, S, S]

BindIOKL is a lens-based version of BindIOK.

func BindL

func BindL[R, C, E, S, T any](
	lens Lens[S, T],
	f func(T) ReaderReaderIOEither[R, C, E, T],
) Operator[R, C, E, S, S]

BindL is a lens-based version of Bind that uses a lens to focus on a specific field in the context.

func BindReaderIOK

func BindReaderIOK[C, E, R, S1, S2, T any](
	setter func(T) func(S1) S2,
	f readerio.Kleisli[R, S1, T],
) Operator[R, C, E, S1, S2]

BindReaderIOK binds a computation that returns a ReaderIO to the context. The Kleisli function is automatically lifted into ReaderReaderIOEither.

func BindReaderIOKL

func BindReaderIOKL[C, E, R, S, T any](
	lens Lens[S, T],
	f readerio.Kleisli[R, T, T],
) Operator[R, C, E, S, S]

BindReaderIOKL is a lens-based version of BindReaderIOK.

func BindReaderK

func BindReaderK[C, E, R, S1, S2, T any](
	setter func(T) func(S1) S2,
	f reader.Kleisli[R, S1, T],
) Operator[R, C, E, S1, S2]

BindReaderK binds a computation that returns a Reader to the context. The Kleisli function is automatically lifted into ReaderReaderIOEither.

func BindReaderKL

func BindReaderKL[C, E, R, S, T any](
	lens Lens[S, T],
	f reader.Kleisli[R, T, T],
) Operator[R, C, E, S, S]

BindReaderKL is a lens-based version of BindReaderK.

func BindTo

func BindTo[R, C, E, S1, T any](
	setter func(T) S1,
) Operator[R, C, E, T, S1]

BindTo wraps a value of type T into a context S1 using the provided setter function. This is typically used as the first operation after Do to initialize the context.

Example:

F.Pipe1(
    readerreaderioeither.Of[OuterEnv, InnerEnv, error](42),
    readerreaderioeither.BindTo(func(n int) State { return State{Count: n} }),
)

func Chain

func Chain[R, C, E, A, B any](f Kleisli[R, C, E, A, B]) Operator[R, C, 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 ChainEitherK

func ChainEitherK[R, C, E, A, B any](f either.Kleisli[E, A, B]) Operator[R, C, E, A, B]

ChainEitherK returns a function that chains an Either-returning function into ReaderReaderIOEither. This is the curried version of MonadChainEitherK.

func ChainFirst

func ChainFirst[R, C, E, A, B any](f Kleisli[R, C, E, A, B]) Operator[R, C, E, A, A]

ChainFirst returns a function that sequences computations but keeps the first result. This is the curried version of MonadChainFirst.

func ChainFirstEitherK

func ChainFirstEitherK[R, C, E, A, B any](f either.Kleisli[E, A, B]) Operator[R, C, E, A, A]

ChainFirstEitherK returns a function that chains an Either computation while preserving the original value. This is the curried version of MonadChainFirstEitherK.

func ChainFirstIOK

func ChainFirstIOK[R, C, E, A, B any](f io.Kleisli[A, B]) Operator[R, C, E, A, A]

ChainFirstIOK returns a function that chains an IO computation while preserving the original value. This is the curried version of MonadChainFirstIOK.

func ChainFirstReaderEitherK

func ChainFirstReaderEitherK[C, E, R, A, B any](f RE.Kleisli[R, E, A, B]) Operator[R, C, E, A, A]

ChainFirstReaderEitherK returns a function that chains a ReaderEither computation while preserving the original value. This is the curried version of MonadChainFirstReaderEitherK.

func ChainFirstReaderIOK

func ChainFirstReaderIOK[C, E, R, A, B any](f readerio.Kleisli[R, A, B]) Operator[R, C, E, A, A]

ChainFirstReaderIOK returns a function that chains a ReaderIO computation while preserving the original value. This is the curried version of MonadChainFirstReaderIOK.

func ChainFirstReaderK

func ChainFirstReaderK[C, E, R, A, B any](f reader.Kleisli[R, A, B]) Operator[R, C, E, A, A]

ChainFirstReaderK returns a function that chains a Reader computation while preserving the original value. This is the curried version of MonadChainFirstReaderK.

func ChainIOEitherK

func ChainIOEitherK[R, C, E, A, B any](f IOE.Kleisli[E, A, B]) Operator[R, C, E, A, B]

ChainIOEitherK returns a function that chains an IOEither-returning function into ReaderReaderIOEither. This is the curried version of MonadChainIOEitherK.

func ChainIOK

func ChainIOK[R, C, E, A, B any](f io.Kleisli[A, B]) Operator[R, C, E, A, B]

ChainIOK returns a function that chains an IO-returning function into ReaderReaderIOEither. This is the curried version of MonadChainIOK.

func ChainReaderEitherK

func ChainReaderEitherK[C, E, R, A, B any](f RE.Kleisli[R, E, A, B]) Operator[R, C, E, A, B]

ChainReaderEitherK returns a function that chains a ReaderEither-returning function into ReaderReaderIOEither. This is the curried version of MonadChainReaderEitherK.

func ChainReaderIOEitherK added in v2.2.1

func ChainReaderIOEitherK[C, R, E, A, B any](f RIOE.Kleisli[R, E, A, B]) Operator[R, C, E, A, B]

ChainReaderIOEitherK returns a function that chains a ReaderIOEither-returning function into ReaderReaderIOEither.

func ChainReaderIOK

func ChainReaderIOK[C, E, R, A, B any](f readerio.Kleisli[R, A, B]) Operator[R, C, E, A, B]

ChainReaderIOK returns a function that chains a ReaderIO-returning function into ReaderReaderIOEither. This is the curried version of MonadChainReaderIOK.

func ChainReaderK

func ChainReaderK[C, E, R, A, B any](f reader.Kleisli[R, A, B]) Operator[R, C, E, A, B]

ChainReaderK returns a function that chains a Reader-returning function into ReaderReaderIOEither. This is the curried version of MonadChainReaderK.

func Delay

func Delay[R, C, E, A any](delay time.Duration) Operator[R, C, E, A, A]

Delay creates an operation that passes in the value after some delay.

func Flap

func Flap[R, C, E, B, A any](a A) Operator[R, C, E, func(A) B, B]

Flap returns a function that applies a fixed value to a function in a context. This is the curried version of MonadFlap.

func Let

func Let[R, C, E, S1, S2, T any](
	setter func(T) func(S1) S2,
	f func(S1) T,
) Operator[R, C, E, S1, S2]

Let attaches a pure computation result to a context [S1] to produce a context [S2]. Unlike Bind, the computation function f is pure (doesn't perform effects).

Example:

readerreaderioeither.Let(
    func(fullName string) func(State) State {
        return func(s State) State { s.FullName = fullName; return s }
    },
    func(s State) string {
        return s.FirstName + " " + s.LastName
    },
)

func LetL

func LetL[R, C, E, S, T any](
	lens Lens[S, T],
	f func(T) T,
) Operator[R, C, E, S, S]

LetL is a lens-based version of Let that uses a lens to focus on a specific field in the context.

func LetTo

func LetTo[R, C, E, S1, S2, T any](
	setter func(T) func(S1) S2,
	b T,
) Operator[R, C, E, S1, S2]

LetTo attaches a constant value to a context [S1] to produce a context [S2].

Example:

readerreaderioeither.LetTo(
    func(status string) func(State) State {
        return func(s State) State { s.Status = status; return s }
    },
    "active",
)

func LetToL

func LetToL[R, C, E, S, T any](
	lens Lens[S, T],
	b T,
) Operator[R, C, E, S, S]

LetToL is a lens-based version of LetTo that uses a lens to focus on a specific field in the context.

func Map

func Map[R, C, E, A, B any](f func(A) B) Operator[R, C, E, A, B]

Map returns a function that applies a transformation to the success value. This is the curried version of MonadMap.

func MapTo

func MapTo[R, C, E, A, B any](b B) Operator[R, C, E, A, B]

MapTo returns a function that replaces the success value with a constant. This is the curried version of MonadMapTo.

func Tap

func Tap[R, C, E, A, B any](f Kleisli[R, C, E, A, B]) Operator[R, C, E, A, A]

Tap is an alias for ChainFirst, executing a side effect while preserving the original value.

func TapEitherK

func TapEitherK[R, C, E, A, B any](f either.Kleisli[E, A, B]) Operator[R, C, E, A, A]

TapEitherK is an alias for ChainFirstEitherK, executing an Either side effect while preserving the original value.

func TapIOK

func TapIOK[R, C, E, A, B any](f io.Kleisli[A, B]) Operator[R, C, E, A, A]

TapIOK is an alias for ChainFirstIOK, executing an IO side effect while preserving the original value.

func TapReaderEitherK

func TapReaderEitherK[C, E, R, A, B any](f RE.Kleisli[R, E, A, B]) Operator[R, C, E, A, A]

TapReaderEitherK is an alias for ChainFirstReaderEitherK, executing a ReaderEither side effect while preserving the original value.

func TapReaderIOK

func TapReaderIOK[C, E, R, A, B any](f readerio.Kleisli[R, A, B]) Operator[R, C, E, A, A]

TapReaderIOK is an alias for ChainFirstReaderIOK, executing a ReaderIO side effect while preserving the original value.

func TapReaderK

func TapReaderK[C, E, R, A, B any](f reader.Kleisli[R, A, B]) Operator[R, C, E, A, A]

TapReaderK is an alias for ChainFirstReaderK, executing a Reader side effect while preserving the original value.

type Option

type Option[A any] = option.Option[A]

Option represents an optional value that may or may not be present. It's an alias for option.Option[A].

type Predicate

type Predicate[A any] = predicate.Predicate[A]

Predicate represents a function that tests a value of type A and returns a boolean. It's an alias for predicate.Predicate[A].

type Reader

type Reader[R, A any] = reader.Reader[R, A]

Reader represents a computation that depends on an environment R and produces a value A. It's an alias for reader.Reader[R, A].

type ReaderEither added in v2.1.17

type ReaderEither[R, E, A any] = readereither.ReaderEither[R, E, A]

ReaderEither represents a computation that depends on an environment R and produces either an error E or a value A. It's an alias for readereither.ReaderEither[R, E, A].

type ReaderIO

type ReaderIO[R, A any] = readerio.ReaderIO[R, A]

ReaderIO represents a computation that depends on an environment R and performs side effects to produce a value A. It's an alias for readerio.ReaderIO[R, A].

type ReaderIOEither

type ReaderIOEither[R, E, A any] = readerioeither.ReaderIOEither[R, E, A]

ReaderIOEither represents a computation that depends on an environment R, performs side effects, and produces either an error E or a value A. It's an alias for readerioeither.ReaderIOEither[R, E, A].

type ReaderOption

type ReaderOption[R, A any] = readeroption.ReaderOption[R, A]

ReaderOption represents a computation that depends on an environment R and produces an optional value A. It's an alias for readeroption.ReaderOption[R, A].

type ReaderReaderIOEither

type ReaderReaderIOEither[R, C, E, A any] = Reader[R, ReaderIOEither[C, E, A]]

ReaderReaderIOEither represents a nested Reader monad transformer that: 1. Takes an outer environment R 2. Returns a ReaderIOEither that takes an inner environment C 3. Performs side effects 4. Produces either an error E or a value A

This is the core type of this package, enabling computations with two levels of environment dependencies, side effects, and error handling.

Type Parameters:

  • R: The outer environment type (first Reader layer)
  • C: The inner environment type (ReaderIOEither layer)
  • E: The error type
  • A: The success value type

Example:

type OuterConfig struct { DatabaseURL string }
type InnerContext struct { RequestID string }

computation := func(outer OuterConfig) readerioeither.ReaderIOEither[InnerContext, error, string] {
    return func(inner InnerContext) ioeither.IOEither[error, string] {
        return func() either.Either[error, string] {
            return either.Right[error](fmt.Sprintf("DB: %s, Request: %s",
                outer.DatabaseURL, inner.RequestID))
        }
    }
}

func Ask

func Ask[R, C, E any]() ReaderReaderIOEither[R, C, E, R]

Ask returns a ReaderReaderIOEither that retrieves the outer context.

func Asks

func Asks[C, E, R, A any](r Reader[R, A]) ReaderReaderIOEither[R, C, E, A]

Asks returns a ReaderReaderIOEither that retrieves a value derived from the outer context.

func Bracket

func Bracket[
	R, C, E, A, B, ANY any](
	acquire ReaderReaderIOEither[R, C, E, A],
	use Kleisli[R, C, E, A, B],
	release func(A, Either[E, B]) ReaderReaderIOEither[R, C, E, ANY],
) ReaderReaderIOEither[R, C, E, B]

Bracket ensures that a resource is properly cleaned up regardless of whether the operation succeeds or fails. It follows the acquire-use-release pattern with access to both outer (R) and inner (C) reader contexts.

The release action is always called after the use action completes, whether it succeeds or fails. This makes it ideal for managing resources like file handles, database connections, or locks.

Parameters:

  • acquire: Acquires the resource, returning a ReaderReaderIOEither[R, C, E, A]
  • use: Uses the acquired resource to perform an operation, returning ReaderReaderIOEither[R, C, E, B]
  • release: Releases the resource, receiving both the resource and the result of use

Returns:

  • A ReaderReaderIOEither[R, C, E, B] that safely manages the resource lifecycle

The release function receives:

  • The acquired resource (A)
  • The result of the use function (Either[E, B])

Example:

type OuterConfig struct {
    ConnectionPool string
}
type InnerConfig struct {
    Timeout time.Duration
}

// Acquire a database connection
acquire := func(outer OuterConfig) readerioeither.ReaderIOEither[InnerConfig, error, *sql.DB] {
    return func(inner InnerConfig) ioeither.IOEither[error, *sql.DB] {
        return ioeither.TryCatch(
            func() (*sql.DB, error) {
                return sql.Open("postgres", outer.ConnectionPool)
            },
            func(err error) error { return err },
        )
    }
}

// Use the connection
use := func(db *sql.DB) readerreaderioeither.ReaderReaderIOEither[OuterConfig, InnerConfig, error, []User] {
    return func(outer OuterConfig) readerioeither.ReaderIOEither[InnerConfig, error, []User] {
        return func(inner InnerConfig) ioeither.IOEither[error, []User] {
            return queryUsers(db, inner.Timeout)
        }
    }
}

// Release the connection
release := func(db *sql.DB, result either.Either[error, []User]) readerreaderioeither.ReaderReaderIOEither[OuterConfig, InnerConfig, error, any] {
    return func(outer OuterConfig) readerioeither.ReaderIOEither[InnerConfig, error, any] {
        return func(inner InnerConfig) ioeither.IOEither[error, any] {
            return ioeither.TryCatch(
                func() (any, error) {
                    return nil, db.Close()
                },
                func(err error) error { return err },
            )
        }
    }
}

result := readerreaderioeither.Bracket(acquire, use, release)

func Defer added in v2.2.1

func Defer[R, C, E, A any](fa Lazy[ReaderReaderIOEither[R, C, E, A]]) ReaderReaderIOEither[R, C, E, A]

Defer creates a ReaderReaderIOEither lazily via a generator function. The generator is called each time the ReaderReaderIOEither is executed.

func Do

func Do[R, C, E, S any](
	empty S,
) ReaderReaderIOEither[R, C, 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 with two reader contexts.

Example:

type State struct {
    User   User
    Posts  []Post
}
type OuterEnv struct {
    Database string
}
type InnerEnv struct {
    UserRepo UserRepository
    PostRepo PostRepository
}
result := readerreaderioeither.Do[OuterEnv, InnerEnv, error](State{})

func Flatten

func Flatten[R, C, E, A any](mma ReaderReaderIOEither[R, C, E, ReaderReaderIOEither[R, C, E, A]]) ReaderReaderIOEither[R, C, E, A]

Flatten removes one level of nesting from a nested ReaderReaderIOEither.

func FromEither

func FromEither[R, C, E, A any](t Either[E, A]) ReaderReaderIOEither[R, C, E, A]

FromEither lifts an Either into a ReaderReaderIOEither context.

func FromIO

func FromIO[R, C, E, A any](ma IO[A]) ReaderReaderIOEither[R, C, E, A]

FromIO lifts an IO into a ReaderReaderIOEither context.

func FromIOEither

func FromIOEither[R, C, E, A any](ma IOEither[E, A]) ReaderReaderIOEither[R, C, E, A]

FromIOEither lifts an IOEither into a ReaderReaderIOEither context.

func FromReader

func FromReader[C, E, R, A any](ma Reader[R, A]) ReaderReaderIOEither[R, C, E, A]

FromReader lifts a Reader into a ReaderReaderIOEither context.

func FromReaderEither

func FromReaderEither[R, C, E, A any](ma RE.ReaderEither[R, E, A]) ReaderReaderIOEither[R, C, E, A]

FromReaderEither lifts a ReaderEither into a ReaderReaderIOEither context.

func FromReaderIO

func FromReaderIO[C, E, R, A any](ma ReaderIO[R, A]) ReaderReaderIOEither[R, C, E, A]

FromReaderIO lifts a ReaderIO into a ReaderReaderIOEither, placing the result in the Right side.

func FromReaderIOEither

func FromReaderIOEither[C, E, R, A any](ma ReaderIOEither[R, E, A]) ReaderReaderIOEither[R, C, E, A]

FromReaderIOEither lifts a ReaderIOEither into a ReaderReaderIOEither context.

func Left

func Left[R, C, A, E any](e E) ReaderReaderIOEither[R, C, E, A]

Left creates a failed ReaderReaderIOEither with the given error.

func LeftIO

func LeftIO[R, C, A, E any](ma IO[E]) ReaderReaderIOEither[R, C, E, A]

LeftIO lifts an IO into a ReaderReaderIOEither, placing the result in the Left (error) side.

func LeftReader

func LeftReader[C, A, R, E any](ma Reader[R, E]) ReaderReaderIOEither[R, C, E, A]

LeftReader lifts a Reader into a ReaderReaderIOEither, placing the result in the Left (error) side.

func LeftReaderIO

func LeftReaderIO[C, A, R, E any](me ReaderIO[R, E]) ReaderReaderIOEither[R, C, E, A]

LeftReaderIO lifts a ReaderIO into a ReaderReaderIOEither, placing the result in the Left (error) side.

func MonadAlt

func MonadAlt[R, C, E, A any](first ReaderReaderIOEither[R, C, E, A], second Lazy[ReaderReaderIOEither[R, C, E, A]]) ReaderReaderIOEither[R, C, E, A]

MonadAlt tries the first computation, and if it fails, tries the second.

func MonadAp

func MonadAp[R, C, E, A, B any](fab ReaderReaderIOEither[R, C, E, func(A) B], fa ReaderReaderIOEither[R, C, E, A]) ReaderReaderIOEither[R, C, E, B]

MonadAp applies a function wrapped in a context to a value wrapped in a context.

func MonadApPar

func MonadApPar[R, C, E, A, B any](fab ReaderReaderIOEither[R, C, E, func(A) B], fa ReaderReaderIOEither[R, C, E, A]) ReaderReaderIOEither[R, C, E, B]

MonadApPar applies a function in a context to a value in a context, executing them in parallel.

func MonadApSeq

func MonadApSeq[R, C, E, A, B any](fab ReaderReaderIOEither[R, C, E, func(A) B], fa ReaderReaderIOEither[R, C, E, A]) ReaderReaderIOEither[R, C, E, B]

MonadApSeq applies a function in a context to a value in a context, executing them sequentially.

func MonadChain

func MonadChain[R, C, E, A, B any](fa ReaderReaderIOEither[R, C, E, A], f Kleisli[R, C, E, A, B]) ReaderReaderIOEither[R, C, E, B]

MonadChain sequences two computations where the second depends on the result of the first.

func MonadChainEitherK

func MonadChainEitherK[R, C, E, A, B any](ma ReaderReaderIOEither[R, C, E, A], f either.Kleisli[E, A, B]) ReaderReaderIOEither[R, C, E, B]

MonadChainEitherK chains a computation that returns an Either into a ReaderReaderIOEither.

func MonadChainFirst

func MonadChainFirst[R, C, E, A, B any](fa ReaderReaderIOEither[R, C, E, A], f Kleisli[R, C, E, A, B]) ReaderReaderIOEither[R, C, 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, C, E, A, B any](ma ReaderReaderIOEither[R, C, E, A], f either.Kleisli[E, A, B]) ReaderReaderIOEither[R, C, E, A]

MonadChainFirstEitherK chains an Either-returning computation but keeps the original value.

func MonadChainFirstIOK

func MonadChainFirstIOK[R, C, E, A, B any](ma ReaderReaderIOEither[R, C, E, A], f io.Kleisli[A, B]) ReaderReaderIOEither[R, C, E, A]

MonadChainFirstIOK chains an IO computation but keeps the original value.

func MonadChainFirstReaderEitherK

func MonadChainFirstReaderEitherK[R, C, E, A, B any](ma ReaderReaderIOEither[R, C, E, A], f RE.Kleisli[R, E, A, B]) ReaderReaderIOEither[R, C, E, A]

MonadChainFirstReaderEitherK chains a ReaderEither computation but keeps the original value.

func MonadChainFirstReaderIOK

func MonadChainFirstReaderIOK[C, E, R, A, B any](ma ReaderReaderIOEither[R, C, E, A], f readerio.Kleisli[R, A, B]) ReaderReaderIOEither[R, C, E, A]

MonadChainFirstReaderIOK chains a ReaderIO computation but keeps the original value.

func MonadChainFirstReaderK

func MonadChainFirstReaderK[C, E, R, A, B any](ma ReaderReaderIOEither[R, C, E, A], f reader.Kleisli[R, A, B]) ReaderReaderIOEither[R, C, E, A]

MonadChainFirstReaderK chains a Reader computation but keeps the original value.

func MonadChainIOEitherK

func MonadChainIOEitherK[R, C, E, A, B any](ma ReaderReaderIOEither[R, C, E, A], f IOE.Kleisli[E, A, B]) ReaderReaderIOEither[R, C, E, B]

MonadChainIOEitherK chains an IOEither-returning computation into a ReaderReaderIOEither.

func MonadChainIOK

func MonadChainIOK[R, C, E, A, B any](ma ReaderReaderIOEither[R, C, E, A], f io.Kleisli[A, B]) ReaderReaderIOEither[R, C, E, B]

MonadChainIOK chains an IO-returning computation into a ReaderReaderIOEither.

func MonadChainLeft

func MonadChainLeft[R, C, EA, EB, A any](fa ReaderReaderIOEither[R, C, EA, A], f Kleisli[R, C, EB, EA, A]) ReaderReaderIOEither[R, C, EB, A]

MonadChainLeft chains a computation on the error channel, allowing error recovery or transformation.

func MonadChainReaderEitherK

func MonadChainReaderEitherK[R, C, E, A, B any](ma ReaderReaderIOEither[R, C, E, A], f RE.Kleisli[R, E, A, B]) ReaderReaderIOEither[R, C, E, B]

MonadChainReaderEitherK chains a ReaderEither-returning computation into a ReaderReaderIOEither.

func MonadChainReaderIOK

func MonadChainReaderIOK[C, E, R, A, B any](ma ReaderReaderIOEither[R, C, E, A], f readerio.Kleisli[R, A, B]) ReaderReaderIOEither[R, C, E, B]

MonadChainReaderIOK chains a ReaderIO-returning computation into a ReaderReaderIOEither.

func MonadChainReaderK

func MonadChainReaderK[C, E, R, A, B any](ma ReaderReaderIOEither[R, C, E, A], f reader.Kleisli[R, A, B]) ReaderReaderIOEither[R, C, E, B]

MonadChainReaderK chains a Reader-returning computation into a ReaderReaderIOEither.

func MonadFlap

func MonadFlap[R, C, E, B, A any](fab ReaderReaderIOEither[R, C, E, func(A) B], a A) ReaderReaderIOEither[R, C, E, B]

MonadFlap applies a value to a function wrapped in a context.

func MonadMap

func MonadMap[R, C, E, A, B any](fa ReaderReaderIOEither[R, C, E, A], f func(A) B) ReaderReaderIOEither[R, C, E, B]

MonadMap applies a function to the value inside a ReaderReaderIOEither context. If the computation is successful (Right), the function is applied to the value.

func MonadMapLeft

func MonadMapLeft[R, C, E1, E2, A any](fa ReaderReaderIOEither[R, C, E1, A], f func(E1) E2) ReaderReaderIOEither[R, C, E2, A]

MonadMapLeft applies a function to the error value, leaving success unchanged.

func MonadMapTo

func MonadMapTo[R, C, E, A, B any](fa ReaderReaderIOEither[R, C, E, A], b B) ReaderReaderIOEither[R, C, E, B]

MonadMapTo replaces the success value with a constant value.

func MonadTap

func MonadTap[R, C, E, A, B any](fa ReaderReaderIOEither[R, C, E, A], f Kleisli[R, C, E, A, B]) ReaderReaderIOEither[R, C, E, A]

MonadTap is an alias for MonadChainFirst, executing a side effect while preserving the original value.

func MonadTapEitherK

func MonadTapEitherK[R, C, E, A, B any](ma ReaderReaderIOEither[R, C, E, A], f either.Kleisli[E, A, B]) ReaderReaderIOEither[R, C, E, A]

MonadTapEitherK is an alias for MonadChainFirstEitherK, executing an Either side effect while preserving the original value.

func MonadTapIOK

func MonadTapIOK[R, C, E, A, B any](ma ReaderReaderIOEither[R, C, E, A], f io.Kleisli[A, B]) ReaderReaderIOEither[R, C, E, A]

MonadTapIOK is an alias for MonadChainFirstIOK, executing an IO side effect while preserving the original value.

func MonadTapReaderEitherK

func MonadTapReaderEitherK[R, C, E, A, B any](ma ReaderReaderIOEither[R, C, E, A], f RE.Kleisli[R, E, A, B]) ReaderReaderIOEither[R, C, E, A]

MonadTapReaderEitherK is an alias for MonadChainFirstReaderEitherK, executing a ReaderEither side effect while preserving the original value.

func MonadTapReaderIOK

func MonadTapReaderIOK[C, E, R, A, B any](ma ReaderReaderIOEither[R, C, E, A], f readerio.Kleisli[R, A, B]) ReaderReaderIOEither[R, C, E, A]

MonadTapReaderIOK is an alias for MonadChainFirstReaderIOK, executing a ReaderIO side effect while preserving the original value.

func MonadTapReaderK

func MonadTapReaderK[C, E, R, A, B any](ma ReaderReaderIOEither[R, C, E, A], f reader.Kleisli[R, A, B]) ReaderReaderIOEither[R, C, E, A]

MonadTapReaderK is an alias for MonadChainFirstReaderK, executing a Reader side effect while preserving the original value.

func Of

func Of[R, C, E, A any](a A) ReaderReaderIOEither[R, C, E, A]

Of creates a successful ReaderReaderIOEither with the given value. This is the pointed functor operation.

func Retrying

func Retrying[R, C, E, A any](
	policy retry.RetryPolicy,
	action Kleisli[R, C, E, retry.RetryStatus, A],
	check Predicate[Either[E, A]],
) ReaderReaderIOEither[R, C, E, A]

Retrying retries an action according to a retry policy until it succeeds or the policy gives up. The action receives a RetryStatus that tracks the retry attempt number and cumulative delay. The check predicate determines whether a result should trigger a retry.

This is useful for operations that may fail transiently and need to be retried with backoff, while having access to both outer (R) and inner (C) reader contexts.

Parameters:

  • policy: The retry policy that determines delays and when to give up
  • action: A Kleisli function that takes RetryStatus and returns a ReaderReaderIOEither
  • check: A predicate that returns true if the result should trigger a retry

Returns:

  • A ReaderReaderIOEither that will retry according to the policy

Example:

type OuterConfig struct {
    MaxRetries int
}
type InnerConfig struct {
    Endpoint string
}

// Retry a network call with exponential backoff
policy := retry.ExponentialBackoff(100*time.Millisecond, 2.0)

action := func(status retry.RetryStatus) readerreaderioeither.ReaderReaderIOEither[OuterConfig, InnerConfig, error, Response] {
    return func(outer OuterConfig) readerioeither.ReaderIOEither[InnerConfig, error, Response] {
        return func(inner InnerConfig) ioeither.IOEither[error, Response] {
            return ioeither.TryCatch(
                func() (Response, error) {
                    return makeRequest(inner.Endpoint)
                },
                func(err error) error { return err },
            )
        }
    }
}

// Retry on network errors
check := func(result either.Either[error, Response]) bool {
    return either.IsLeft(result) && isNetworkError(either.GetLeft(result))
}

result := readerreaderioeither.Retrying(policy, action, check)
func Right[R, C, E, A any](a A) ReaderReaderIOEither[R, C, E, A]

Right creates a successful ReaderReaderIOEither with the given value.

func RightIO

func RightIO[R, C, E, A any](ma IO[A]) ReaderReaderIOEither[R, C, E, A]

RightIO lifts an IO into a ReaderReaderIOEither, placing the result in the Right side.

func RightReader

func RightReader[C, E, R, A any](ma Reader[R, A]) ReaderReaderIOEither[R, C, E, A]

RightReader lifts a Reader into a ReaderReaderIOEither, placing the result in the Right side.

func RightReaderIO

func RightReaderIO[C, E, R, A any](ma ReaderIO[R, A]) ReaderReaderIOEither[R, C, E, A]

RightReaderIO lifts a ReaderIO into a ReaderReaderIOEither, placing the result in the Right side.

type Trampoline

type Trampoline[L, B any] = tailrec.Trampoline[L, B]

Trampoline represents a tail-recursive computation that can be executed without stack overflow. It's an alias for tailrec.Trampoline[L, B].

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL