readerioresult

package
v2.2.21 Latest Latest
Warning

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

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

Documentation

Overview

package readerioresult provides a functional programming abstraction that combines three powerful concepts: Reader, IO, and Either monads.

Fantasy Land Specification

This is a monad transformer combining:

Implemented Fantasy Land algebras:

ReaderIOResult

ReaderIOResult[R, 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 ReaderIOResult
  • FromIO: Lift an IO into ReaderIOResult
  • FromReader: Lift a Reader into ReaderIOResult
  • FromIOEither: Lift an IOEither into ReaderIOResult
  • 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 ReaderIOResult

Combination:

  • Ap: Apply a function in a context to a value in a context
  • SequenceArray: Convert array of ReaderIOResult to ReaderIOResult 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.ReaderIOResult[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.ReaderIOResult[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

Constants

This section is empty.

Variables

This section is empty.

Functions

func BiMap

func BiMap[R, E, A, B any](f func(error) E, g func(A) B) func(ReaderIOResult[R, A]) RIOE.ReaderIOEither[R, E, 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 any](onNone Lazy[error]) func(readeroption.Kleisli[R, A, B]) Operator[R, A, A]

func ChainLeft

func ChainLeft[R, A any](f Kleisli[R, error, A]) func(ReaderIOResult[R, A]) ReaderIOResult[R, A]

func ChainOptionK

func ChainOptionK[R, A, B any](onNone Lazy[error]) func(func(A) Option[B]) Operator[R, A, B]

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

func ChainReaderOptionK

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

func Eitherize0

func Eitherize0[F ~func(C) (R, error), C, R any](f F) func() ReaderIOResult[C, R]

Eitherize0 converts a function with 1 parameters returning a tuple into a function with 0 parameters returning a [ReaderIOResult[C, R]] The first parameter is considered to be the context [C].

func Eitherize1

func Eitherize1[F ~func(C, T0) (R, error), T0, C, R any](f F) func(T0) ReaderIOResult[C, R]

Eitherize1 converts a function with 2 parameters returning a tuple into a function with 1 parameters returning a [ReaderIOResult[C, 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) ReaderIOResult[C, R]

Eitherize2 converts a function with 3 parameters returning a tuple into a function with 2 parameters returning a [ReaderIOResult[C, 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) ReaderIOResult[C, R]

Eitherize3 converts a function with 4 parameters returning a tuple into a function with 3 parameters returning a [ReaderIOResult[C, 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) ReaderIOResult[C, R]

Eitherize4 converts a function with 5 parameters returning a tuple into a function with 4 parameters returning a [ReaderIOResult[C, 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) ReaderIOResult[C, R]

Eitherize5 converts a function with 6 parameters returning a tuple into a function with 5 parameters returning a [ReaderIOResult[C, 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) ReaderIOResult[C, R]

Eitherize6 converts a function with 7 parameters returning a tuple into a function with 6 parameters returning a [ReaderIOResult[C, 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) ReaderIOResult[C, R]

Eitherize7 converts a function with 8 parameters returning a tuple into a function with 7 parameters returning a [ReaderIOResult[C, 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) ReaderIOResult[C, R]

Eitherize8 converts a function with 9 parameters returning a tuple into a function with 8 parameters returning a [ReaderIOResult[C, 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) ReaderIOResult[C, R]

Eitherize9 converts a function with 10 parameters returning a tuple into a function with 9 parameters returning a [ReaderIOResult[C, 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) ReaderIOResult[C, R]

Eitherize10 converts a function with 11 parameters returning a tuple into a function with 10 parameters returning a [ReaderIOResult[C, R]] The first parameter is considered to be the context [C].

func Eq

func Eq[R, A any](eq eq.Eq[Result[A]]) func(R) eq.Eq[ReaderIOResult[R, A]]

Eq implements the equals predicate for values contained in the IOEither monad

func Fold

func Fold[R, A, B any](onLeft readerio.Kleisli[R, error, B], onRight func(A) ReaderIO[R, B]) func(ReaderIOResult[R, A]) ReaderIO[R, B]

Fold handles both success and error cases, producing a ReaderIO. This is useful for converting a ReaderIOResult into a ReaderIO by handling all cases.

func From0

func From0[F ~func(C) func() (R, error), C, R any](f F) func() ReaderIOResult[C, R]

From0 converts a function with 1 parameters returning a tuple into a function with 0 parameters returning a [ReaderIOResult[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) ReaderIOResult[C, R]

From1 converts a function with 2 parameters returning a tuple into a function with 1 parameters returning a [ReaderIOResult[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) ReaderIOResult[C, R]

From2 converts a function with 3 parameters returning a tuple into a function with 2 parameters returning a [ReaderIOResult[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) ReaderIOResult[C, R]

From3 converts a function with 4 parameters returning a tuple into a function with 3 parameters returning a [ReaderIOResult[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) ReaderIOResult[C, R]

From4 converts a function with 5 parameters returning a tuple into a function with 4 parameters returning a [ReaderIOResult[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) ReaderIOResult[C, R]

From5 converts a function with 6 parameters returning a tuple into a function with 5 parameters returning a [ReaderIOResult[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) ReaderIOResult[C, R]

From6 converts a function with 7 parameters returning a tuple into a function with 6 parameters returning a [ReaderIOResult[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) ReaderIOResult[C, R]

From7 converts a function with 8 parameters returning a tuple into a function with 7 parameters returning a [ReaderIOResult[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) ReaderIOResult[C, R]

From8 converts a function with 9 parameters returning a tuple into a function with 8 parameters returning a [ReaderIOResult[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) ReaderIOResult[C, R]

From9 converts a function with 10 parameters returning a tuple into a function with 9 parameters returning a [ReaderIOResult[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) ReaderIOResult[C, R]

From10 converts a function with 11 parameters returning a tuple into a function with 10 parameters returning a [ReaderIOResult[R]] The first parameter is considered to be the context [C].

func FromStrictEquals

func FromStrictEquals[R any, A comparable]() func(R) eq.Eq[ReaderIOResult[R, A]]

FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function

func Functor

func Functor[R, A, B any]() functor.Functor[A, B, ReaderIOResult[R, A], ReaderIOResult[R, B]]

Functor returns the functor operations for ReaderIOResult

func GetOrElse

func GetOrElse[R, A any](onLeft readerio.Kleisli[R, error, A]) func(ReaderIOResult[R, 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[A, R1, R2 any](f func(R2) R1) func(ReaderIOResult[R1, A]) ReaderIOResult[R2, 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, E any](f func(error) E) func(ReaderIOResult[R, A]) RIOE.ReaderIOEither[R, E, A]

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

func Monad

func Monad[R, A, B any]() monad.Monad[A, B, ReaderIOResult[R, A], ReaderIOResult[R, B], ReaderIOResult[R, func(A) B]]

Monad returns the monadic operations for ReaderIOResult

func MonadBiMap

func MonadBiMap[R, E, A, B any](fa ReaderIOResult[R, A], f func(error) E, g func(A) B) RIOE.ReaderIOEither[R, E, B]

MonadBiMap applies two functions: one to the error, one to the success value. This allows transforming both channels simultaneously.

func MonadMapLeft

func MonadMapLeft[R, E, A any](fa ReaderIOResult[R, A], f func(error) E) RIOE.ReaderIOEither[R, E, A]

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

func OrLeft

func OrLeft[A, R, E any](onLeft readerio.Kleisli[R, error, E]) func(ReaderIOResult[R, A]) RIOE.ReaderIOEither[R, E, A]

OrLeft transforms the error using a ReaderIO if the computation fails. The success value is preserved unchanged.

func Pointed

func Pointed[R, A any]() pointed.Pointed[A, ReaderIOResult[R, A]]

Pointed returns the pointed operations for ReaderIOResult

func Read

func Read[A, R any](r R) func(ReaderIOResult[R, A]) IOResult[A]

func ReadIO added in v2.1.10

func ReadIO[A, R any](r IO[R]) func(ReaderIOResult[R, A]) IOResult[A]

ReadIO executes a ReaderIOResult computation by providing an environment obtained from an IO computation. Unlike ReadIOEither/ReadIOResult, the environment acquisition cannot fail (it's a pure IO, not IOResult).

The function first executes the IO[R] to obtain the environment, then uses that environment to run the ReaderIOResult[R, A] computation.

Type parameters:

  • A: The success value type of the ReaderIOResult computation
  • R: The environment/context type required by the ReaderIOResult

Parameters:

  • r: An IO[R] that produces the environment (cannot fail)

Returns:

  • A function that takes a ReaderIOResult[R, A] and returns IOResult[A]

Example:

type Logger struct { Level string }

// Get logger (always succeeds)
getLogger := func() IO[Logger] {
    return func() Logger {
        return Logger{Level: "INFO"}
    }
}

// Log operation that may fail
logMessage := func(msg string) ReaderIOResult[Logger, string] {
    return func(logger Logger) IOResult[string] {
        return func() Result[string] {
            // Log with logger, may fail
            return result.Of(fmt.Sprintf("[%s] %s", logger.Level, msg))
        }
    }
}

// Execute logging with logger
logged := ReadIO[string](getLogger())(logMessage("Hello"))()

func ReadIOEither added in v2.1.10

func ReadIOEither[A, R any](r IOResult[R]) func(ReaderIOResult[R, A]) IOResult[A]

ReadIOEither executes a ReaderIOResult computation by providing an environment obtained from an IOResult. This function bridges the gap between IOResult-based environment acquisition and ReaderIOResult-based computations.

The function first executes the IOResult[R] to obtain the environment (or an error), then uses that environment to run the ReaderIOResult[R, A] computation.

Type parameters:

  • A: The success value type of the ReaderIOResult computation
  • R: The environment/context type required by the ReaderIOResult

Parameters:

  • r: An IOResult[R] that produces the environment (or an error)

Returns:

  • A function that takes a ReaderIOResult[R, A] and returns IOResult[A]

Example:

type Config struct { BaseURL string }

// Get config from environment with potential error
getConfig := func() IOResult[Config] {
    return func() Result[Config] {
        // Load config, may fail
        return result.Of(Config{BaseURL: "https://api.example.com"})
    }
}

// A computation that needs config
fetchUser := func(id int) ReaderIOResult[Config, User] {
    return func(cfg Config) IOResult[User] {
        return func() Result[User] {
            // Use cfg.BaseURL to fetch user
            return result.Of(User{ID: id})
        }
    }
}

// Execute the computation with the config
result := ReadIOEither[User](getConfig())(fetchUser(123))()

func ReadIOResult added in v2.1.10

func ReadIOResult[A, R any](r IOResult[R]) func(ReaderIOResult[R, A]) IOResult[A]

ReadIOResult executes a ReaderIOResult computation by providing an environment obtained from an IOResult. This is an alias for ReadIOEither with more explicit naming.

The function first executes the IOResult[R] to obtain the environment (or an error), then uses that environment to run the ReaderIOResult[R, A] computation.

Type parameters:

  • A: The success value type of the ReaderIOResult computation
  • R: The environment/context type required by the ReaderIOResult

Parameters:

  • r: An IOResult[R] that produces the environment (or an error)

Returns:

  • A function that takes a ReaderIOResult[R, A] and returns IOResult[A]

Example:

type Database struct { ConnectionString string }

// Get database connection with potential error
getDB := func() IOResult[Database] {
    return func() Result[Database] {
        return result.Of(Database{ConnectionString: "localhost:5432"})
    }
}

// Query that needs database
queryUsers := ReaderIOResult[Database, []User] {
    return func(db Database) IOResult[[]User] {
        return func() Result[[]User] {
            // Execute query using db
            return result.Of([]User{})
        }
    }
}

// Execute query with database
users := ReadIOResult[[]User](getDB())(queryUsers)()

func Swap

func Swap[R, A any](val ReaderIOResult[R, A]) RIOE.ReaderIOEither[R, A, error]

Swap exchanges the error and success types. Left becomes Right and Right becomes Left.

func TapReaderOptionK

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

func Traverse

func Traverse[R2, R1, A, B any](
	f Kleisli[R1, A, B],
) func(ReaderIOResult[R2, A]) Kleisli[R2, R1, B]

func TraverseReader

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

func Uneitherize0

func Uneitherize0[F ~func() ReaderIOResult[C, R], C, R any](f F) func(C) (R, error)

Uneitherize0 converts a function with 1 parameters returning a [ReaderIOResult[C, 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) ReaderIOResult[C, R], T0, C, R any](f F) func(C, T0) (R, error)

Uneitherize1 converts a function with 2 parameters returning a [ReaderIOResult[C, R]] into a function with 1 parameters returning a tuple. The first parameter is considered to be the context [C].

func Uneitherize2

func Uneitherize2[F ~func(T0, T1) ReaderIOResult[C, R], T0, T1, C, R any](f F) func(C, T0, T1) (R, error)

Uneitherize2 converts a function with 3 parameters returning a [ReaderIOResult[C, 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) ReaderIOResult[C, 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 [ReaderIOResult[C, 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) ReaderIOResult[C, 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 [ReaderIOResult[C, 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) ReaderIOResult[C, 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 [ReaderIOResult[C, 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) ReaderIOResult[C, 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 [ReaderIOResult[C, 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) ReaderIOResult[C, 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 [ReaderIOResult[C, 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) ReaderIOResult[C, 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 [ReaderIOResult[C, 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) ReaderIOResult[C, 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 [ReaderIOResult[C, R]] into a function with 9 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) ReaderIOResult[C, 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 [ReaderIOResult[C, R]] into a function with 10 parameters returning a tuple. The first parameter is considered to be the context [C].

Types

type Consumer

type Consumer[A any] = consumer.Consumer[A]

Consumer represents a function that consumes a value of type A.

type Either

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

Either represents a value of one of two possible types (a disjoint union).

type Endomorphism

type Endomorphism[A any] = endomorphism.Endomorphism[A]

Endomorphism represents a function from a type to itself (A -> A).

type IO

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

IO represents a synchronous computation that cannot fail.

type IOEither

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

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 IOResult

type IOResult[A any] = ioresult.IOResult[A]

IOResult represents a synchronous computation that may fail with an error.

type Kleisli

type Kleisli[R, A, B any] = reader.Reader[A, ReaderIOResult[R, B]]

Kleisli represents a Kleisli arrow for the ReaderIOResult monad. It's a function from A to ReaderIOResult[R, B], used for composing operations that depend on an environment, perform side effects, and may fail.

func Contramap added in v2.1.6

func Contramap[A, R1, R2 any](f func(R2) R1) Kleisli[R2, ReaderIOResult[R1, A], A]

Contramap changes the value of the local environment during the execution of a ReaderIOResult. This is the contravariant functor operation that transforms the input environment.

See: https://github.com/fantasyland/fantasy-land?tab=readme-ov-file#profunctor

Contramap is useful for adapting a ReaderIOResult to work with a different environment type by providing a function that converts the new environment to the expected one.

Type Parameters:

  • A: The success type (unchanged)
  • R2: The new input environment type
  • R1: The original environment type expected by the ReaderIOResult

Parameters:

  • f: Function to transform the environment from R2 to R1

Returns:

  • A Kleisli arrow that takes a ReaderIOResult[R1, A] and returns a ReaderIOResult[R2, A]

func FromOption

func FromOption[R, A any](onNone Lazy[error]) Kleisli[R, Option[A], A]

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

func FromPredicate

func FromPredicate[R, A any](pred func(A) bool, onFalse func(A) error) Kleisli[R, A, A]

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

func FromReaderOption

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

func LocalIOEitherK added in v2.2.1

func LocalIOEitherK[A, R1, R2 any](f ioeither.Kleisli[error, R2, R1]) Kleisli[R2, ReaderIOResult[R1, A], A]

LocalIOEitherK transforms the environment of a ReaderIOResult using an IOEither-based Kleisli arrow. It allows you to modify the environment through an effectful computation that can fail before passing it to the ReaderIOResult.

This is useful when the environment transformation itself requires IO effects that can fail, such as reading from a file that might not exist, making a network call that might timeout, or parsing data that might be invalid.

The transformation happens in two stages:

  1. The IOEither effect f is executed with the R2 environment to produce Either[error, R1]
  2. If successful (Right), the R1 value is passed to the ReaderIOResult[R1, A]
  3. If failed (Left), the error is propagated without executing the ReaderIOResult

Type Parameters:

  • A: The success type produced by the ReaderIOResult
  • R1: The original environment type expected by the ReaderIOResult
  • R2: The new input environment type

Parameters:

  • f: An IOEither Kleisli arrow that transforms R2 to R1 with IO effects that can fail

Returns:

  • A Kleisli arrow that takes a ReaderIOResult[R1, A] and returns a ReaderIOResult[R2, A]

Example:

// Transform a config path into a loaded config (can fail)
loadConfig := func(path string) IOEither[error, Config] {
    return func() Either[error, Config] {
        cfg, err := readConfigFile(path)
        if err != nil {
            return Left[Config](err)
        }
        return Right[error](cfg)
    }
}

// Use the config to perform an operation that might fail
useConfig := func(cfg Config) IOResult[string] {
    return func() Result[string] {
        if cfg.Valid {
            return Ok[string]("Success: " + cfg.Name)
        }
        return Err[string](errors.New("invalid config"))
    }
}

// Compose them using LocalIOEitherK
result := LocalIOEitherK[string, Config, string](loadConfig)(useConfig)
output := result("config.json")() // Loads config (might fail) and uses it (might fail)

func LocalIOK added in v2.2.1

func LocalIOK[A, R1, R2 any](f io.Kleisli[R2, R1]) Kleisli[R2, ReaderIOResult[R1, A], A]

LocalIOK transforms the environment of a ReaderIOResult using an IO-based Kleisli arrow. It allows you to modify the environment through an effectful computation before passing it to the ReaderIOResult.

This is useful when the environment transformation itself requires IO effects, such as reading from a file, making a network call, or accessing system resources, but these effects cannot fail (or failures are not relevant).

The transformation happens in two stages:

  1. The IO effect f is executed with the R2 environment to produce an R1 value
  2. The resulting R1 value is passed to the ReaderIOResult[R1, A] to produce the final result

Type Parameters:

  • A: The success type produced by the ReaderIOResult
  • R1: The original environment type expected by the ReaderIOResult
  • R2: The new input environment type

Parameters:

  • f: An IO Kleisli arrow that transforms R2 to R1 with IO effects

Returns:

  • A Kleisli arrow that takes a ReaderIOResult[R1, A] and returns a ReaderIOResult[R2, A]

Example:

// Transform a config path into a loaded config (infallible)
loadConfig := func(path string) IO[Config] {
    return func() Config {
        return getDefaultConfig() // Always succeeds
    }
}

// Use the config to perform an operation that might fail
useConfig := func(cfg Config) IOResult[string] {
    return func() Result[string] {
        if cfg.Valid {
            return Ok[string]("Success")
        }
        return Err[string](errors.New("invalid config"))
    }
}

// Compose them using LocalIOK
result := LocalIOK[string, Config, string](loadConfig)(useConfig)
output := result("config.json")() // Loads config and uses it

func LocalIOResultK added in v2.2.1

func LocalIOResultK[A, R1, R2 any](f ioresult.Kleisli[R2, R1]) Kleisli[R2, ReaderIOResult[R1, A], A]

LocalIOResultK transforms the environment of a ReaderIOResult using an IOResult-based Kleisli arrow. It allows you to modify the environment through an effectful computation that can fail before passing it to the ReaderIOResult.

This is a type-safe alias for LocalIOEitherK specialized for error type, providing a more idiomatic API when working with Result types (which use error as the error type).

The transformation happens in two stages:

  1. The IOResult effect f is executed with the R2 environment to produce Result[R1]
  2. If successful (Ok), the R1 value is passed to the ReaderIOResult[R1, A]
  3. If failed (Err), the error is propagated without executing the ReaderIOResult

Type Parameters:

  • A: The success type produced by the ReaderIOResult
  • R1: The original environment type expected by the ReaderIOResult
  • R2: The new input environment type

Parameters:

  • f: An IOResult Kleisli arrow that transforms R2 to R1 with IO effects that can fail

Returns:

  • A Kleisli arrow that takes a ReaderIOResult[R1, A] and returns a ReaderIOResult[R2, A]

Example:

// Transform a config path into a loaded config (can fail)
loadConfig := func(path string) IOResult[Config] {
    return func() Result[Config] {
        cfg, err := readConfigFile(path)
        if err != nil {
            return Err[Config](err)
        }
        return Ok(cfg)
    }
}

// Use the config to perform an operation that might fail
useConfig := func(cfg Config) IOResult[string] {
    return func() Result[string] {
        if cfg.Valid {
            return Ok("Success: " + cfg.Name)
        }
        return Err[string](errors.New("invalid config"))
    }
}

// Compose them using LocalIOResultK
result := LocalIOResultK[string, Config, string](loadConfig)(useConfig)
output := result("config.json")() // Loads config (might fail) and uses it (might fail)

func Promap added in v2.1.6

func Promap[R, A, D, B any](f func(D) R, g func(A) B) Kleisli[D, ReaderIOResult[R, A], B]

Promap is the profunctor map operation that transforms both the input and output of a ReaderIOResult. It applies f to the input environment (contravariantly) and g to the output value (covariantly).

See: https://github.com/fantasyland/fantasy-land?tab=readme-ov-file#profunctor

This operation allows you to:

  • Adapt the environment type before passing it to the ReaderIOResult (via f)
  • Transform the success value after the IO effect completes (via g)

The error type is fixed as error and remains unchanged through the transformation.

Type Parameters:

  • R: The original environment type expected by the ReaderIOResult
  • A: The original success type produced by the ReaderIOResult
  • D: The new input environment type
  • B: The new output success type

Parameters:

  • f: Function to transform the input environment from D to R (contravariant)
  • g: Function to transform the output success value from A to B (covariant)

Returns:

  • A Kleisli arrow that takes a ReaderIOResult[R, A] and returns a ReaderIOResult[D, B]

func ReduceArray

func ReduceArray[R, A, B any](reduce func(B, A) B, initial B) Kleisli[R, []ReaderIOResult[R, A], B]

ReduceArray returns a curried function that reduces an array of ReaderIOResults to a single ReaderIOResult. This is the curried version where the reduction function and initial value are provided first, returning a function that takes the array of ReaderIOResults.

Parameters:

  • reduce: Binary function that combines accumulated value with each ReaderIOResult's result
  • initial: Starting value for the reduction

Returns:

  • A function that takes an array of ReaderIOResults and returns a ReaderIOResult of the reduced result

Example:

type Config struct { Multiplier int }
product := func(acc, val int) int { return acc * val }
reducer := readerioresult.ReduceArray[Config](product, 1)
readers := []readerioresult.ReaderIOResult[Config, int]{
    readerioresult.Of[Config](func(c Config) int { return c.Multiplier * 2 }),
    readerioresult.Of[Config](func(c Config) int { return c.Multiplier * 3 }),
}
r := reducer(readers)
result := r(Config{Multiplier: 5})() // result.Of(150) (10 * 15)

func ReduceArrayM

func ReduceArrayM[R, A any](m monoid.Monoid[A]) Kleisli[R, []ReaderIOResult[R, A], A]

ReduceArrayM returns a curried function that reduces an array of ReaderIOResults using a Monoid. This is the curried version where the Monoid is provided first, returning a function that takes the array of ReaderIOResults.

The Monoid provides both the binary operation (Concat) and the identity element (Empty) for the reduction.

Parameters:

  • m: Monoid that defines how to combine the ReaderIOResult results

Returns:

  • A function that takes an array of ReaderIOResults and returns a ReaderIOResult of the reduced result

Example:

type Config struct { Scale int }
intMultMonoid := monoid.MakeMonoid(func(a, b int) int { return a * b }, 1)
reducer := readerioresult.ReduceArrayM[Config](intMultMonoid)
readers := []readerioresult.ReaderIOResult[Config, int]{
    readerioresult.Of[Config](func(c Config) int { return c.Scale }),
    readerioresult.Of[Config](func(c Config) int { return c.Scale * 2 }),
}
r := reducer(readers)
result := r(Config{Scale: 3})() // result.Of(18) (3 * 6)

func Sequence

func Sequence[R1, R2, A any](ma ReaderIOResult[R2, ReaderIOResult[R1, A]]) Kleisli[R2, R1, A]

func SequenceReader

func SequenceReader[R1, R2, A any](ma ReaderIOResult[R2, Reader[R1, A]]) Kleisli[R2, R1, A]

func SequenceReaderEither

func SequenceReaderEither[R1, R2, A any](ma ReaderIOResult[R2, ReaderResult[R1, A]]) Kleisli[R2, R1, A]

func SequenceReaderIO

func SequenceReaderIO[R1, R2, A any](ma ReaderIOResult[R2, ReaderIO[R1, A]]) Kleisli[R2, R1, A]

func SequenceReaderResult

func SequenceReaderResult[R1, R2, A any](ma ReaderIOResult[R2, ReaderResult[R1, A]]) Kleisli[R2, R1, A]

func TailRec

func TailRec[R, A, B any](f Kleisli[R, A, tailrec.Trampoline[A, B]]) Kleisli[R, A, B]

func TraverseArray

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

TraverseArray transforms each element of an array using a function that returns a ReaderIOResult, then collects the results into a single ReaderIOResult 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 ReaderIOResult

Returns:

A function that takes an array and returns a ReaderIOResult of an array

Example:

fetchUsers := TraverseArray(func(id int) ReaderIOResult[Config, error, User] {
    return fetchUser(id)
})
result := fetchUsers([]int{1, 2, 3})
// result(cfg)() returns Right([user1, user2, user3]) or Left(error)

func TraverseArrayWithIndex

func TraverseArrayWithIndex[R, A, B any](f func(int, A) ReaderIOResult[R, B]) Kleisli[R, []A, []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 ReaderIOResult

Returns:

A function that takes an array and returns a ReaderIOResult of an array

Example:

processWithIndex := TraverseArrayWithIndex(func(i int, val string) ReaderIOResult[Config, error, string] {
    return Of[Config, error](fmt.Sprintf("%d: %s", i, val))
})

func TraverseRecord

func TraverseRecord[K comparable, R, A, B any](f Kleisli[R, A, B]) Kleisli[R, map[K]A, map[K]B]

TraverseRecord transforms each value in a map using a function that returns a ReaderIOResult, then collects the results into a single ReaderIOResult 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 ReaderIOResult

Returns:

A function that takes a map and returns a ReaderIOResult of a map

Example:

enrichUsers := TraverseRecord(func(user User) ReaderIOResult[Config, error, EnrichedUser] {
    return enrichUser(user)
})
result := enrichUsers(map[string]User{"alice": user1, "bob": user2})

func TraverseRecordWithIndex

func TraverseRecordWithIndex[K comparable, R, A, B any](f func(K, A) ReaderIOResult[R, B]) Kleisli[R, map[K]A, 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 ReaderIOResult

Returns:

A function that takes a map and returns a ReaderIOResult of a map

Example:

processWithKey := TraverseRecordWithIndex(func(key string, val int) ReaderIOResult[Config, error, string] {
    return Of[Config, error](fmt.Sprintf("%s: %d", key, val))
})

func TraverseReduceArray

func TraverseReduceArray[R, A, B, C any](trfrm Kleisli[R, A, B], reduce func(C, B) C, initial C) Kleisli[R, []A, C]

TraverseReduceArray returns a curried function that transforms and reduces an array. This is the curried version where the transformation function, reduce function, and initial value are provided first, returning a function that takes the array.

First, each element is transformed using the provided Kleisli function into a ReaderIOResult. Then, the ReaderIOResult results are reduced using the provided reduction function.

Parameters:

  • trfrm: Function that transforms each element into a ReaderIOResult
  • reduce: Binary function that combines accumulated value with each transformed result
  • initial: Starting value for the reduction

Returns:

  • A function that takes an array and returns a ReaderIOResult of the reduced result

Example:

type Config struct { Base int }
addBase := func(n int) readerioresult.ReaderIOResult[Config, int] {
    return readerioresult.Of[Config](func(c Config) int { return n + c.Base })
}
product := func(acc, val int) int { return acc * val }
transformer := readerioresult.TraverseReduceArray(addBase, product, 1)
r := transformer([]int{2, 3, 4})
result := r(Config{Base: 10})() // result.Of(2184) (12 * 13 * 14)

func TraverseReduceArrayM

func TraverseReduceArrayM[R, A, B any](trfrm Kleisli[R, A, B], m monoid.Monoid[B]) Kleisli[R, []A, B]

TraverseReduceArrayM returns a curried function that transforms and reduces an array using a Monoid. This is the curried version where the transformation function and Monoid are provided first, returning a function that takes the array.

First, each element is transformed using the provided Kleisli function into a ReaderIOResult. Then, the ReaderIOResult results are reduced using the Monoid's binary operation and identity element.

Parameters:

  • trfrm: Function that transforms each element into a ReaderIOResult
  • m: Monoid that defines how to combine the transformed results

Returns:

  • A function that takes an array and returns a ReaderIOResult of the reduced result

Example:

type Config struct { Factor int }
scale := func(n int) readerioresult.ReaderIOResult[Config, int] {
    return readerioresult.Of[Config](func(c Config) int { return n * c.Factor })
}
intProdMonoid := monoid.MakeMonoid(func(a, b int) int { return a * b }, 1)
transformer := readerioresult.TraverseReduceArrayM(scale, intProdMonoid)
r := transformer([]int{2, 3, 4})
result := r(Config{Factor: 5})() // result.Of(3000) (10 * 15 * 20)

func WithResource

func WithResource[A, L, R, ANY any](onCreate ReaderIOResult[L, R], onRelease Kleisli[L, R, ANY]) Kleisli[L, Kleisli[L, 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:

  1. onCreate: Acquires the resource
  2. use: Operates on the resource (provided as argument to the returned function)
  3. 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 ReaderIOResult that manages the resource lifecycle

Example:

withFile := WithResource(
    openFile("data.txt"),
    func(f *File) ReaderIOResult[Config, error, int] {
        return closeFile(f)
    },
)
result := withFile(func(f *File) ReaderIOResult[Config, error, string] {
    return readContent(f)
})

type Lazy

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

Lazy represents a deferred computation that produces a value of type A.

type Monoid

type Monoid[R, A any] = monoid.Monoid[ReaderIOResult[R, A]]

func AltMonoid

func AltMonoid[R, A any](zero lazy.Lazy[ReaderIOResult[R, A]]) Monoid[R, A]

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

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

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

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

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

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

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

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

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, A, B any] = Kleisli[R, ReaderIOResult[R, A], B]

Operator represents a transformation from one ReaderIOResult to another. It's a Reader that takes a ReaderIOResult[R, A] and produces a ReaderIOResult[R, B]. This type is commonly used for composing operations in a point-free style.

Type parameters:

  • R: The context type
  • A: The input value type
  • B: The output value type

Example:

var doubleOp Operator[Config, error, int, int] = Map(N.Mul(2))

func After

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

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

func Alt

func Alt[R, A any](second Lazy[ReaderIOResult[R, A]]) Operator[R, 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, A any](fa ReaderIOResult[R, A]) Operator[R, 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, S1, S2, T any](
	setter func(T) func(S1) S2,
	fa Result[T],
) Operator[R, S1, S2]

ApEitherS is an applicative variant that works with Either (Result) values. It lifts an Either value into the ReaderIOResult context using applicative composition.

Parameters:

  • setter: Updates state from S1 to S2 using result T
  • fa: An Either value

Example:

parseResult := result.TryCatch(func() (int, error) {
    return strconv.Atoi("123")
})

func ApEitherSL

func ApEitherSL[R, S, T any](
	lens L.Lens[S, T],
	fa Result[T],
) Operator[R, S, S]

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

Example:

valueLens := lens.MakeLens(
    func(s State) int { return s.Value },
    func(s State, v int) State { s.Value = v; return s },
)
parseValue := result.TryCatch(func() (int, error) {
    return strconv.Atoi("123")
})

func ApIOEitherS

func ApIOEitherS[R, S1, S2, T any](
	setter func(T) func(S1) S2,
	fa IOResult[T],
) Operator[R, 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 (not a Kleisli arrow)

Example:

readConfig := ioeither.TryCatch(func() (Config, error) {
    return loadConfig()
})

func ApIOEitherSL

func ApIOEitherSL[R, S, T any](
	lens L.Lens[S, T],
	fa IOResult[T],
) Operator[R, S, S]

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

Example:

userLens := lens.MakeLens(
    func(s State) User { return s.User },
    func(s State, u User) State { s.User = u; return s },
)
loadUser := ioeither.TryCatch(func() (User, error) {
    return fetchUser()
})

func ApIOResultS

func ApIOResultS[R, S1, S2, T any](
	setter func(T) func(S1) S2,
	fa IOResult[T],
) Operator[R, S1, S2]

ApIOResultS is an applicative variant that works with IOResult values. This is an alias for ApIOEitherS for consistency with the Result naming convention.

Parameters:

  • setter: Updates state from S1 to S2 using result T
  • fa: An IOResult value

func ApIOResultSL

func ApIOResultSL[R, S, T any](
	lens L.Lens[S, T],
	fa IOResult[T],
) Operator[R, S, S]

ApIOResultSL is a lens-based variant of ApIOResultS. This is an alias for ApIOEitherSL for consistency with the Result naming convention.

Parameters:

  • lens: A lens focusing on field T within state S
  • fa: An IOResult value

func ApIOS

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

ApIOS is an applicative variant that works with IO values. It lifts an IO value into the ReaderIOResult context using applicative composition.

Parameters:

  • setter: Updates state from S1 to S2 using result T
  • fa: An IO value

Example:

getCurrentTime := func() time.Time { return time.Now() }

func ApIOSL

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

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

Example:

timestampLens := lens.MakeLens(
    func(s State) time.Time { return s.Timestamp },
    func(s State, t time.Time) State { s.Timestamp = t; return s },
)
getCurrentTime := func() time.Time { return time.Now() }

func ApReaderIOS

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

ApReaderIOS is an applicative variant that works with ReaderIO values. It lifts a ReaderIO value into the ReaderIOResult context using applicative composition.

Parameters:

  • setter: Updates state from S1 to S2 using result T
  • fa: A ReaderIO value

func ApReaderIOSL

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

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

Example:

logLens := lens.MakeLens(
    func(s State) string { return s.LogMessage },
    func(s State, l string) State { s.LogMessage = l; return s },
)
logWithEnv := func(env Env) io.IO[string] {
    return func() string {
        env.Logger.Println("Processing")
        return "logged"
    }
}

func ApReaderS

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

ApReaderS is an applicative variant that works with Reader values. It lifts a Reader value into the ReaderIOResult context using applicative composition.

Parameters:

  • setter: Updates state from S1 to S2 using result T
  • fa: A Reader value

Example:

getEnvConfig := func(env Env) string { return env.ConfigValue }

func ApReaderSL

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

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

Example:

configLens := lens.MakeLens(
    func(s State) string { return s.Config },
    func(s State, c string) State { s.Config = c; return s },
)
getConfig := func(env Env) string { return env.ConfigValue }

func ApResultS

func ApResultS[R, S1, S2, T any](
	setter func(T) func(S1) S2,
	fa Result[T],
) Operator[R, S1, S2]

ApResultS is an applicative variant that works with Result values. This is an alias for ApEitherS for consistency with the Result naming convention.

Parameters:

  • setter: Updates state from S1 to S2 using result T
  • fa: A Result value

func ApResultSL

func ApResultSL[R, S, T any](
	lens L.Lens[S, T],
	fa Result[T],
) Operator[R, S, S]

ApResultSL is a lens-based variant of ApResultS. This is an alias for ApEitherSL for consistency with the Result naming convention.

Parameters:

  • lens: A lens focusing on field T within state S
  • fa: A Result value

func ApS

func ApS[R, S1, S2, T any](
	setter func(T) func(S1) S2,
	fa ReaderIOResult[R, T],
) Operator[R, 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

func ApSL[R, S, T any](
	lens L.Lens[S, T],
	fa ReaderIOResult[R, T],
) Operator[R, S, S]

ApSL attaches a value to a context using a lens-based setter. This is a convenience function that combines ApS with a lens, allowing you to use optics to update nested structures in a more composable way.

The lens parameter provides both the getter and setter for a field within the structure S. This eliminates the need to manually write setter functions.

Example:

type State struct {
    User   User
    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, S1, S2, T any](
	setter func(T) func(S1) S2,
	f Kleisli[R, S1, T],
) Operator[R, 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.ReaderIOResult[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.ReaderIOResult[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, S1, S2, T any](
	setter func(T) func(S1) S2,
	f result.Kleisli[S1, T],
) Operator[R, S1, S2]

BindEitherK is a variant of Bind that works with Either (Result) computations. It lifts an Either Kleisli arrow into the ReaderIOResult context.

Parameters:

  • setter: Updates state from S1 to S2 using result T
  • f: An Either Kleisli arrow (S1 -> Either[error, T])

Example:

parseValue := func(s State) result.Result[int] {
    return result.TryCatch(func() (int, error) {
        return strconv.Atoi(s.StringValue)
    })
}

func BindIOEitherK

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

BindIOEitherK is a variant of Bind that works with IOEither computations. It lifts an IOEither Kleisli arrow into the ReaderIOResult context, allowing you to compose IOEither operations within a do-notation chain.

This is useful when you have an existing IOEither computation that doesn't need access to the Reader environment, and you want to integrate it into a ReaderIOResult pipeline.

Parameters:

  • setter: A function that takes the result T and returns a function to update the state from S1 to S2
  • f: An IOEither Kleisli arrow that takes S1 and returns IOEither[error, T]

Returns:

  • An Operator that can be used in a do-notation chain

Example:

type State struct {
    UserID int
    Data   []byte
}

// An IOEither operation that reads a file
readFile := func(s State) ioeither.IOEither[error, []byte] {
    return ioeither.TryCatch(func() ([]byte, error) {
        return os.ReadFile(fmt.Sprintf("user_%d.json", s.UserID))
    })
}

result := F.Pipe2(
    readerioresult.Do[Env, error](State{UserID: 123}),
    readerioresult.BindIOEitherK(
        func(data []byte) func(State) State {
            return func(s State) State { s.Data = data; return s }
        },
        readFile,
    ),
)

func BindIOEitherKL

func BindIOEitherKL[R, S, T any](
	lens L.Lens[S, T],
	f ioresult.Kleisli[T, T],
) Operator[R, 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[error, T])

Example:

userLens := lens.MakeLens(
    func(s State) User { return s.User },
    func(s State, u User) State { s.User = u; return s },
)
updateUser := func(u User) ioeither.IOEither[error, User] {
    return ioeither.TryCatch(func() (User, error) {
        return saveUser(u)
    })
}
result := F.Pipe2(
    readerioresult.Do[Env](State{}),
    readerioresult.BindIOEitherKL(userLens, updateUser),
)

func BindIOK

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

BindIOK is a variant of Bind that works with IO computations. It lifts an IO Kleisli arrow into the ReaderIOResult context.

Parameters:

  • setter: Updates state from S1 to S2 using result T
  • f: An IO Kleisli arrow (S1 -> IO[T])

Example:

getCurrentTime := func(s State) io.IO[time.Time] {
    return func() time.Time { return time.Now() }
}

func BindIOKL

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

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])

Example:

timestampLens := lens.MakeLens(
    func(s State) time.Time { return s.Timestamp },
    func(s State, t time.Time) State { s.Timestamp = t; return s },
)
updateTimestamp := func(t time.Time) io.IO[time.Time] {
    return func() time.Time { return time.Now() }
}

func BindIOResultK

func BindIOResultK[R, S1, S2, T any](
	setter func(T) func(S1) S2,
	f ioresult.Kleisli[S1, T],
) Operator[R, S1, S2]

func BindIOResultKL

func BindIOResultKL[R, S, T any](
	lens L.Lens[S, T],
	f ioresult.Kleisli[T, T],
) Operator[R, S, S]

BindIOResultKL is a lens-based variant of BindIOResultK. It combines a lens with an IOResult Kleisli arrow, focusing on a specific field within the state structure.

Parameters:

  • lens: A lens focusing on field T within state S
  • f: An IOResult Kleisli arrow (T -> IOResult[T])

func BindL

func BindL[R, S, T any](
	lens L.Lens[S, T],
	f Kleisli[R, T, T],
) Operator[R, 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 ReaderIOResult 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.ReaderIOResult[Env, error, User] {
        return readerioeither.Asks(func(env Env) ioeither.IOEither[error, User] {
            return env.UserRepo.FindUser()
        })
    }),
)

func BindReaderIOK

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

BindReaderIOK is a variant of Bind that works with ReaderIO computations. It lifts a ReaderIO Kleisli arrow into the ReaderIOResult context.

Parameters:

  • setter: Updates state from S1 to S2 using result T
  • f: A ReaderIO Kleisli arrow (S1 -> ReaderIO[R, T])

Example:

logState := func(s State) readerio.ReaderIO[Env, string] {
    return func(env Env) io.IO[string] {
        return func() string {
            env.Logger.Println(s)
            return "logged"
        }
    }
}

func BindReaderIOKL

func BindReaderIOKL[R, S, T any](
	lens L.Lens[S, T],
	f readerio.Kleisli[R, T, T],
) Operator[R, 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])

Example:

logLens := lens.MakeLens(
    func(s State) string { return s.LogMessage },
    func(s State, l string) State { s.LogMessage = l; return s },
)
logMessage := func(msg string) readerio.ReaderIO[Env, string] {
    return func(env Env) io.IO[string] {
        return func() string {
            env.Logger.Println(msg)
            return "logged: " + msg
        }
    }
}

func BindReaderK

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

BindReaderK is a variant of Bind that works with Reader computations. It lifts a Reader Kleisli arrow into the ReaderIOResult context.

Parameters:

  • setter: Updates state from S1 to S2 using result T
  • f: A Reader Kleisli arrow (S1 -> Reader[R, T])

Example:

getConfig := func(s State) reader.Reader[Env, string] {
    return func(env Env) string { return env.ConfigValue }
}

func BindReaderKL

func BindReaderKL[R, S, T any](
	lens L.Lens[S, T],
	f reader.Kleisli[R, T, T],
) Operator[R, 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])

Example:

configLens := lens.MakeLens(
    func(s State) string { return s.Config },
    func(s State, c string) State { s.Config = c; return s },
)
getConfigFromEnv := func(c string) reader.Reader[Env, string] {
    return func(env Env) string { return env.ConfigValue }
}

func BindResultK

func BindResultK[R, S1, S2, T any](
	setter func(T) func(S1) S2,
	f result.Kleisli[S1, T],
) Operator[R, S1, S2]

func BindTo

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

BindTo initializes a new state [S1] from a value [T]

func Chain

func Chain[R, A, B any](f Kleisli[R, A, B]) Operator[R, 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, A any](c Consumer[A]) Operator[R, A, Void]

ChainConsumer chains a consumer (side-effect function) into a ReaderIOResult computation, replacing the success value with Void (empty struct).

This is useful for performing side effects (like logging, printing, or writing to a file) where you don't need to preserve the original value. The consumer is only executed if the computation succeeds; if it fails with an error, the consumer is skipped.

Type parameters:

  • R: The context/environment type
  • A: The value type to consume

Parameters:

  • c: A consumer function that performs a side effect on the value

Returns:

An Operator that executes the consumer and returns Void on success

Example:

import (
    "context"
    "fmt"
    RIO "github.com/IBM/fp-go/v2/readerioresult"
)

// Log a value and discard it
logValue := RIO.ChainConsumer[context.Context](func(x int) {
    fmt.Printf("Value: %d\n", x)
})

computation := F.Pipe1(
    RIO.Of[context.Context](42),
    logValue,
)
// Prints "Value: 42" and returns result.Of(struct{}{})

func ChainEitherK

func ChainEitherK[R, A, B any](f result.Kleisli[A, B]) Operator[R, A, B]

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

func ChainFirst

func ChainFirst[R, A, B any](f Kleisli[R, A, B]) Operator[R, 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, A any](c Consumer[A]) Operator[R, A, A]

ChainFirstConsumer chains a consumer into a ReaderIOResult computation while preserving the original value.

This is useful for performing side effects (like logging, printing, or metrics collection) where you want to keep the original value for further processing. The consumer is only executed if the computation succeeds; if it fails with an error, the consumer is skipped and the error is propagated.

Type parameters:

  • R: The context/environment type
  • A: The value type to consume and preserve

Parameters:

  • c: A consumer function that performs a side effect on the value

Returns:

An Operator that executes the consumer and returns the original value on success

Example:

import (
    "context"
    "fmt"
    F "github.com/IBM/fp-go/v2/function"
    N "github.com/IBM/fp-go/v2/number"
    RIO "github.com/IBM/fp-go/v2/readerioresult"
)

// Log a value but keep it for further processing
logValue := RIO.ChainFirstConsumer[context.Context](func(x int) {
    fmt.Printf("Processing: %d\n", x)
})

computation := F.Pipe2(
    RIO.Of[context.Context](10),
    logValue,
    RIO.Map[context.Context](N.Mul(2)),
)
// Prints "Processing: 10" and returns result.Of(20)

func ChainFirstEitherK

func ChainFirstEitherK[R, A, B any](f result.Kleisli[A, B]) Operator[R, 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, A, B any](f func(A) IO[B]) Operator[R, A, A]

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, B any](f Kleisli[R, error, B]) Operator[R, A, A]

func ChainFirstLeftIOK added in v2.1.1

func ChainFirstLeftIOK[A, R, B any](f io.Kleisli[error, B]) Operator[R, A, A]

func ChainFirstReaderEitherK

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

func ChainFirstReaderIOK

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

func ChainFirstReaderK

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

func ChainFirstReaderResultK

func ChainFirstReaderResultK[R, A, B any](f RE.Kleisli[R, error, A, B]) Operator[R, A, A]

func ChainFirstResultK

func ChainFirstResultK[R, A, B any](f result.Kleisli[A, B]) Operator[R, A, A]

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

func ChainIOEitherK

func ChainIOEitherK[R, A, B any](f func(A) IOResult[B]) Operator[R, A, B]

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

func ChainIOK

func ChainIOK[R, A, B any](f func(A) IO[B]) Operator[R, A, B]

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

func ChainIOResultK

func ChainIOResultK[R, A, B any](f func(A) IOResult[B]) Operator[R, A, B]

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

func ChainReaderEitherK

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

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

func ChainReaderIOK

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

func ChainReaderK

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

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

func ChainReaderResultK

func ChainReaderResultK[R, A, B any](f RE.Kleisli[R, error, A, B]) Operator[R, A, B]

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

func ChainResultK

func ChainResultK[R, A, B any](f result.Kleisli[A, B]) Operator[R, A, B]

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

func Delay

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

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

func FilterOrElse added in v2.1.0

func FilterOrElse[R, A any](pred Predicate[A], onFalse func(A) error) Operator[R, A, A]

FilterOrElse filters a ReaderIOResult value based on a predicate. If the predicate returns true for the Right value, it passes through unchanged. If the predicate returns false, it transforms the Right value into a Left (error) using onFalse. Left values are passed through unchanged.

This is useful for adding validation or constraints to successful computations that depend on a context, converting values that don't meet certain criteria into errors. The error type is fixed as `error` in ReaderIOResult.

Parameters:

  • pred: A predicate function that tests the Right value
  • onFalse: A function that converts the failing value into an error

Returns:

  • An Operator that filters ReaderIOResult values based on the predicate

Example:

type Config struct {
    MaxValue int
}

// Validate that a number doesn't exceed the configured maximum
validateMax := func(cfg Config) readerioresult.ReaderIOResult[Config, int] {
    isValid := func(n int) bool { return n <= cfg.MaxValue }
    onInvalid := func(n int) error {
        return fmt.Errorf("%d exceeds max %d", n, cfg.MaxValue)
    }

    filter := readerioresult.FilterOrElse(isValid, onInvalid)
    return filter(readerioresult.Right[Config](42))
}

cfg := Config{MaxValue: 100}
result := validateMax(cfg)(cfg)() // Right(42)

cfg2 := Config{MaxValue: 10}
result2 := validateMax(cfg2)(cfg2)() // Left(error: "42 exceeds max 10")

func Flap

func Flap[R, B, A any](a A) Operator[R, 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, S1, S2, T any](
	setter func(T) func(S1) S2,
	f func(S1) T,
) Operator[R, S1, S2]

Let attaches the result of a computation to a context [S1] to produce a context [S2]

func LetL

func LetL[R, S, T any](
	lens L.Lens[S, T],
	f func(T) T,
) Operator[R, S, S]

LetL is a variant of Let that uses a lens to focus on a specific part of the context. This provides a more ergonomic API when working with nested structures, eliminating the need to manually write setter functions.

The lens parameter provides both a getter and setter for a field of type T within the context S. The function f receives the current value of the focused field and returns a new value (without wrapping in a ReaderIOResult).

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, S1, S2, T any](
	setter func(T) func(S1) S2,
	b T,
) Operator[R, S1, S2]

LetTo attaches the a value to a context [S1] to produce a context [S2]

func LetToL

func LetToL[R, S, T any](
	lens L.Lens[S, T],
	b T,
) Operator[R, S, S]

LetToL is a variant of LetTo that uses a lens to focus on a specific part of the context. This provides a more ergonomic API when working with nested structures, eliminating the need to manually write setter functions.

The lens parameter provides both a getter and setter for a field of type T within the context S. The value b is set directly to the focused field.

Example:

type State struct {
    User   User
    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, A, B any](f func(A) B) Operator[R, A, B]

Map returns a function that applies a transformation to the success value of a ReaderIOResult. This is the curried version of MonadMap, useful for function composition.

func MapTo

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

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

func OrElse

func OrElse[R, A any](onLeft Kleisli[R, error, A]) Operator[R, A, A]

OrElse tries an alternative computation if the first one fails.

func Tap

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

func TapEitherK

func TapEitherK[R, A, B any](f result.Kleisli[A, B]) Operator[R, A, A]

func TapIOK

func TapIOK[R, A, B any](f func(A) IO[B]) Operator[R, A, A]

func TapLeft

func TapLeft[A, R, B any](f Kleisli[R, error, B]) Operator[R, A, A]

func TapLeftIOK added in v2.1.1

func TapLeftIOK[A, R, B any](f io.Kleisli[error, B]) Operator[R, A, A]

func TapReaderEitherK

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

func TapReaderIOK

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

func TapReaderK

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

func TapReaderResultK

func TapReaderResultK[R, A, B any](f RE.Kleisli[R, error, A, B]) Operator[R, A, A]

func TapResultK

func TapResultK[R, A, B any](f result.Kleisli[A, B]) Operator[R, A, A]

func WithLock

func WithLock[R, A any](lock func() context.CancelFunc) Operator[R, A, A]

WithLock executes a ReaderIOResult 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 Option

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

Option represents an optional value that may or may not be present.

type Predicate added in v2.1.0

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

Predicate represents a function that tests a value of type A and returns a boolean.

type Reader

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

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 ReaderIO

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

ReaderIO represents a computation that depends on some context R and performs side effects to produce a value of type A.

type ReaderIOResult

type ReaderIOResult[R, A any] = Reader[R, IOResult[A]]

ReaderIOResult 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:

  1. Reader monad for dependency injection
  2. IO monad for side effects
  3. 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) ReaderIOResult[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 any]() ReaderIOResult[R, R]

Ask returns a ReaderIOResult that retrieves the current context. Useful for accessing configuration or dependencies.

func Asks

func Asks[R, A any](r Reader[R, A]) ReaderIOResult[R, A]

Asks returns a ReaderIOResult that retrieves a value derived from the context. This is useful for extracting specific fields from a configuration object.

func Bracket

func Bracket[
	R, A, B, ANY any](
	acquire ReaderIOResult[R, A],
	use Kleisli[R, A, B],
	release func(A, Result[B]) ReaderIOResult[R, ANY],
) ReaderIOResult[R, 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

func Defer[R, A any](gen Lazy[ReaderIOResult[R, A]]) ReaderIOResult[R, A]

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

func Do

func Do[R, S any](
	empty S,
) ReaderIOResult[R, 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, A any](mma ReaderIOResult[R, ReaderIOResult[R, A]]) ReaderIOResult[R, A]

Flatten removes one level of nesting from a nested ReaderIOResult. Converts ReaderIOResult[R, ReaderIOResult[R, A]] to ReaderIOResult[R, A].

func FromEither

func FromEither[R, A any](t Result[A]) ReaderIOResult[R, A]

FromEither lifts an Either into a ReaderIOResult context. The Either value is independent of any context or IO effects.

func FromIO

func FromIO[R, A any](ma IO[A]) ReaderIOResult[R, A]

FromIO lifts an IO into a ReaderIOResult context. The IO result is placed in the Right side (success).

func FromIOEither

func FromIOEither[R, A any](ma IOResult[A]) ReaderIOResult[R, A]

FromIOEither lifts an IOEither into a ReaderIOResult context. The computation becomes independent of any reader context.

func FromIOResult

func FromIOResult[R, A any](ma IOResult[A]) ReaderIOResult[R, A]

FromIOEither lifts an IOEither into a ReaderIOResult context. The computation becomes independent of any reader context.

func FromReader

func FromReader[R, A any](ma Reader[R, A]) ReaderIOResult[R, A]

FromReader lifts a Reader into a ReaderIOResult context. The Reader result is placed in the Right side (success).

func FromReaderEither

func FromReaderEither[R, A any](ma RE.ReaderEither[R, error, A]) ReaderIOResult[R, A]

FromReaderEither lifts a ReaderEither into a ReaderIOResult context. The Either result is lifted into an IO effect.

func FromReaderIO

func FromReaderIO[R, A any](ma ReaderIO[R, A]) ReaderIOResult[R, A]

FromReaderIO creates a function that lifts a ReaderIO-producing function into ReaderIOResult. The ReaderIO result is placed in the Right side of the Either.

func FromResult

func FromResult[R, A any](t Result[A]) ReaderIOResult[R, A]

FromResult lifts an Either into a ReaderIOResult context. The Either value is independent of any context or IO effects.

func Left

func Left[R, A any](e error) ReaderIOResult[R, A]

Left creates a failed ReaderIOResult with the given error.

func LeftIO

func LeftIO[R, A any](ma IO[error]) ReaderIOResult[R, A]

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

func LeftReader

func LeftReader[A, R any](ma Reader[R, error]) ReaderIOResult[R, A]

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

func LeftReaderIO

func LeftReaderIO[A, R any](me ReaderIO[R, error]) ReaderIOResult[R, A]

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

func Memoize

func Memoize[R, A any](rdr ReaderIOResult[R, A]) ReaderIOResult[R, A]

Memoize computes the value of the ReaderIOResult 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, A any](first ReaderIOResult[R, A], second Lazy[ReaderIOResult[R, A]]) ReaderIOResult[R, 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, A, B any](fab ReaderIOResult[R, func(A) B], fa ReaderIOResult[R, A]) ReaderIOResult[R, 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, A, B any](fab ReaderIOResult[R, func(A) B], fa ReaderIOResult[R, A]) ReaderIOResult[R, B]

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

func MonadApSeq

func MonadApSeq[R, A, B any](fab ReaderIOResult[R, func(A) B], fa ReaderIOResult[R, A]) ReaderIOResult[R, B]

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

func MonadChain

func MonadChain[R, A, B any](fa ReaderIOResult[R, A], f Kleisli[R, A, B]) ReaderIOResult[R, 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, A, B any](ma ReaderIOResult[R, A], f result.Kleisli[A, B]) ReaderIOResult[R, B]

MonadChainEitherK chains a computation that returns an Either into a ReaderIOResult. The Either is automatically lifted into the ReaderIOResult context.

func MonadChainFirst

func MonadChainFirst[R, A, B any](fa ReaderIOResult[R, A], f Kleisli[R, A, B]) ReaderIOResult[R, 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, A, B any](ma ReaderIOResult[R, A], f result.Kleisli[A, B]) ReaderIOResult[R, 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, A, B any](ma ReaderIOResult[R, A], f func(A) IO[B]) ReaderIOResult[R, 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, B any](ma ReaderIOResult[R, A], f Kleisli[R, error, B]) ReaderIOResult[R, A]

func MonadChainFirstReaderEitherK

func MonadChainFirstReaderEitherK[R, A, B any](ma ReaderIOResult[R, A], f RE.Kleisli[R, error, A, B]) ReaderIOResult[R, A]

func MonadChainFirstReaderIOK

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

func MonadChainFirstReaderK

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

func MonadChainFirstReaderResultK

func MonadChainFirstReaderResultK[R, A, B any](ma ReaderIOResult[R, A], f RE.Kleisli[R, error, A, B]) ReaderIOResult[R, A]

func MonadChainFirstResultK

func MonadChainFirstResultK[R, A, B any](ma ReaderIOResult[R, A], f result.Kleisli[A, B]) ReaderIOResult[R, A]

MonadChainFirstEitherK chains an Either-returning computation but keeps the original value. Useful for validation or side effects that return Either.

func MonadChainIOEitherK

func MonadChainIOEitherK[R, A, B any](ma ReaderIOResult[R, A], f func(A) IOResult[B]) ReaderIOResult[R, B]

MonadChainIOEitherK chains an IOEither-returning computation into a ReaderIOResult. The IOEither is automatically lifted into the ReaderIOResult context.

func MonadChainIOK

func MonadChainIOK[R, A, B any](ma ReaderIOResult[R, A], f func(A) IO[B]) ReaderIOResult[R, B]

MonadChainIOK chains an IO-returning computation into a ReaderIOResult. The IO is automatically lifted into the ReaderIOResult context (always succeeds).

func MonadChainIOResultK

func MonadChainIOResultK[R, A, B any](ma ReaderIOResult[R, A], f func(A) IOResult[B]) ReaderIOResult[R, B]

MonadChainIOEitherK chains an IOEither-returning computation into a ReaderIOResult. The IOEither is automatically lifted into the ReaderIOResult context.

func MonadChainLeft

func MonadChainLeft[R, A any](fa ReaderIOResult[R, A], f Kleisli[R, error, A]) ReaderIOResult[R, A]

func MonadChainReaderEitherK

func MonadChainReaderEitherK[R, A, B any](ma ReaderIOResult[R, A], f RE.Kleisli[R, error, A, B]) ReaderIOResult[R, B]

MonadChainReaderK chains a Reader-returning computation into a ReaderIOResult. The Reader is automatically lifted into the ReaderIOResult context.

func MonadChainReaderIOK

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

func MonadChainReaderK

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

MonadChainReaderK chains a Reader-returning computation into a ReaderIOResult. The Reader is automatically lifted into the ReaderIOResult context.

func MonadChainReaderResultK

func MonadChainReaderResultK[R, A, B any](ma ReaderIOResult[R, A], f RE.Kleisli[R, error, A, B]) ReaderIOResult[R, B]

func MonadChainResultK

func MonadChainResultK[R, A, B any](ma ReaderIOResult[R, A], f result.Kleisli[A, B]) ReaderIOResult[R, B]

MonadChainEitherK chains a computation that returns an Either into a ReaderIOResult. The Either is automatically lifted into the ReaderIOResult context.

func MonadFlap

func MonadFlap[R, B, A any](fab ReaderIOResult[R, func(A) B], a A) ReaderIOResult[R, 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, A, B any](fa ReaderIOResult[R, A], f func(A) B) ReaderIOResult[R, B]

MonadMap applies a function to the value inside a ReaderIOResult 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 MonadMapTo

func MonadMapTo[R, A, B any](fa ReaderIOResult[R, A], b B) ReaderIOResult[R, 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, A, B any](as []ReaderIOResult[R, A], reduce func(B, A) B, initial B) ReaderIOResult[R, B]

MonadReduceArray reduces an array of ReaderIOResults to a single ReaderIOResult by applying a reduction function. This is the monadic version that takes the array of ReaderIOResults as the first parameter.

Each ReaderIOResult is evaluated with the same environment R, and the results are accumulated using the provided reduce function starting from the initial value. If any ReaderIOResult fails, the entire operation fails with that error.

Parameters:

  • as: Array of ReaderIOResults to reduce
  • reduce: Binary function that combines accumulated value with each ReaderIOResult's result
  • initial: Starting value for the reduction

Example:

type Config struct { Base int }
readers := []readerioresult.ReaderIOResult[Config, int]{
    readerioresult.Of[Config](func(c Config) int { return c.Base + 1 }),
    readerioresult.Of[Config](func(c Config) int { return c.Base + 2 }),
    readerioresult.Of[Config](func(c Config) int { return c.Base + 3 }),
}
sum := func(acc, val int) int { return acc + val }
r := readerioresult.MonadReduceArray(readers, sum, 0)
result := r(Config{Base: 10})() // result.Of(36) (11 + 12 + 13)

func MonadReduceArrayM

func MonadReduceArrayM[R, A any](as []ReaderIOResult[R, A], m monoid.Monoid[A]) ReaderIOResult[R, A]

MonadReduceArrayM reduces an array of ReaderIOResults using a Monoid to combine the results. This is the monadic version that takes the array of ReaderIOResults as the first parameter.

The Monoid provides both the binary operation (Concat) and the identity element (Empty) for the reduction, making it convenient when working with monoidal types. If any ReaderIOResult fails, the entire operation fails with that error.

Parameters:

  • as: Array of ReaderIOResults to reduce
  • m: Monoid that defines how to combine the ReaderIOResult results

Example:

type Config struct { Factor int }
readers := []readerioresult.ReaderIOResult[Config, int]{
    readerioresult.Of[Config](func(c Config) int { return c.Factor }),
    readerioresult.Of[Config](func(c Config) int { return c.Factor * 2 }),
    readerioresult.Of[Config](func(c Config) int { return c.Factor * 3 }),
}
intAddMonoid := monoid.MakeMonoid(func(a, b int) int { return a + b }, 0)
r := readerioresult.MonadReduceArrayM(readers, intAddMonoid)
result := r(Config{Factor: 5})() // result.Of(30) (5 + 10 + 15)

func MonadTap

func MonadTap[R, A, B any](fa ReaderIOResult[R, A], f Kleisli[R, A, B]) ReaderIOResult[R, A]

func MonadTapEitherK

func MonadTapEitherK[R, A, B any](ma ReaderIOResult[R, A], f result.Kleisli[A, B]) ReaderIOResult[R, A]

func MonadTapIOK

func MonadTapIOK[R, A, B any](ma ReaderIOResult[R, A], f func(A) IO[B]) ReaderIOResult[R, A]

func MonadTapLeft

func MonadTapLeft[A, R, B any](ma ReaderIOResult[R, A], f Kleisli[R, error, B]) ReaderIOResult[R, A]

func MonadTapReaderEitherK

func MonadTapReaderEitherK[R, A, B any](ma ReaderIOResult[R, A], f RE.Kleisli[R, error, A, B]) ReaderIOResult[R, A]

func MonadTapReaderIOK

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

func MonadTapReaderK

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

func MonadTapReaderResultK

func MonadTapReaderResultK[R, A, B any](ma ReaderIOResult[R, A], f RE.Kleisli[R, error, A, B]) ReaderIOResult[R, A]

func MonadTapResultK

func MonadTapResultK[R, A, B any](ma ReaderIOResult[R, A], f result.Kleisli[A, B]) ReaderIOResult[R, A]

func MonadTraverseReduceArray

func MonadTraverseReduceArray[R, A, B, C any](as []A, trfrm Kleisli[R, A, B], reduce func(C, B) C, initial C) ReaderIOResult[R, C]

MonadTraverseReduceArray transforms and reduces an array in one operation. This is the monadic version that takes the array as the first parameter.

First, each element is transformed using the provided Kleisli function into a ReaderIOResult. Then, the ReaderIOResult results are reduced using the provided reduction function. If any transformation fails, the entire operation fails with that error.

This is more efficient than calling TraverseArray followed by a separate reduce operation, as it combines both operations into a single traversal.

Parameters:

  • as: Array of elements to transform and reduce
  • trfrm: Function that transforms each element into a ReaderIOResult
  • reduce: Binary function that combines accumulated value with each transformed result
  • initial: Starting value for the reduction

Example:

type Config struct { Multiplier int }
numbers := []int{1, 2, 3, 4}
multiply := func(n int) readerioresult.ReaderIOResult[Config, int] {
    return readerioresult.Of[Config](func(c Config) int { return n * c.Multiplier })
}
sum := func(acc, val int) int { return acc + val }
r := readerioresult.MonadTraverseReduceArray(numbers, multiply, sum, 0)
result := r(Config{Multiplier: 10})() // result.Of(100) (10 + 20 + 30 + 40)

func MonadTraverseReduceArrayM

func MonadTraverseReduceArrayM[R, A, B any](as []A, trfrm Kleisli[R, A, B], m monoid.Monoid[B]) ReaderIOResult[R, B]

MonadTraverseReduceArrayM transforms and reduces an array using a Monoid. This is the monadic version that takes the array as the first parameter.

First, each element is transformed using the provided Kleisli function into a ReaderIOResult. Then, the ReaderIOResult results are reduced using the Monoid's binary operation and identity element. If any transformation fails, the entire operation fails with that error.

This combines transformation and monoidal reduction in a single efficient operation.

Parameters:

  • as: Array of elements to transform and reduce
  • trfrm: Function that transforms each element into a ReaderIOResult
  • m: Monoid that defines how to combine the transformed results

Example:

type Config struct { Offset int }
numbers := []int{1, 2, 3}
addOffset := func(n int) readerioresult.ReaderIOResult[Config, int] {
    return readerioresult.Of[Config](func(c Config) int { return n + c.Offset })
}
intSumMonoid := monoid.MakeMonoid(func(a, b int) int { return a + b }, 0)
r := readerioresult.MonadTraverseReduceArrayM(numbers, addOffset, intSumMonoid)
result := r(Config{Offset: 100})() // result.Of(306) (101 + 102 + 103)

func Of

func Of[R, A any](a A) ReaderIOResult[R, A]

Of creates a successful ReaderIOResult with the given value. This is the pointed functor operation, lifting a pure value into the ReaderIOResult context.

func Retrying

func Retrying[R, A any](
	policy retry.RetryPolicy,
	action Kleisli[R, retry.RetryStatus, A],
	check func(Result[A]) bool,
) ReaderIOResult[R, A]

Retrying retries a ReaderIOResult computation according to a retry policy.

This function implements a retry mechanism for operations that depend on a context (Reader), perform side effects (IO), and can fail (Result). It will repeatedly execute the action according to the retry policy until either:

  • The action succeeds and the check function returns false (no retry needed)
  • The retry policy returns None (retry limit reached)
  • The check function returns false (indicating success or a non-retryable failure)

Parameters:

  • policy: A RetryPolicy that determines when and how long to wait between retries. The policy receives a RetryStatus on each iteration and returns an optional delay. If it returns None, retrying stops. Common policies include LimitRetries, ExponentialBackoff, and CapDelay from the retry package.

  • action: A Kleisli arrow that takes a RetryStatus and returns a ReaderIOResult[R, A]. This function is called on each retry attempt and receives information about the current retry state (iteration number, cumulative delay, etc.). The action depends on a context of type R and produces a Result[A].

  • check: A predicate function that examines the Result[A] and returns true if the operation should be retried, or false if it should stop. This allows you to distinguish between retryable failures (e.g., network timeouts) and permanent failures (e.g., invalid input).

Returns:

A ReaderIOResult[R, A] that, when executed with a context, will perform the retry
logic and return the final result.

Type Parameters:

  • R: The type of the context/environment required by the action
  • A: The type of the success value

Example:

type Config struct {
    MaxRetries int
    BaseURL    string
}

// Create a retry policy: exponential backoff with a cap, limited to 5 retries
policy := M.Concat(
    retry.LimitRetries(5),
    retry.CapDelay(10*time.Second, retry.ExponentialBackoff(100*time.Millisecond)),
)(retry.Monoid)

// Action that fetches data, with retry status information
fetchData := func(status retry.RetryStatus) ReaderIOResult[Config, string] {
    return func(cfg Config) IOResult[string] {
        return func() Result[string] {
            // Simulate an HTTP request that might fail
            if status.IterNumber < 3 {
                return result.Left[string](fmt.Errorf("temporary error"))
            }
            return result.Right[error]("success")
        }
    }
}

// Check function: retry on any error
shouldRetry := func(r Result[string]) bool {
    return result.IsLeft(r)
}

// Create the retrying computation
retryingFetch := Retrying(policy, fetchData, shouldRetry)

// Execute with a config
cfg := Config{MaxRetries: 5, BaseURL: "https://api.example.com"}
ioResult := retryingFetch(cfg)
finalResult := ioResult()

See also:

  • retry.RetryPolicy for available retry policies
  • retry.RetryStatus for information passed to the action
  • readerioeither.Retrying for the underlying implementation
func Right[R, A any](a A) ReaderIOResult[R, A]

Right creates a successful ReaderIOResult with the given value.

func RightIO

func RightIO[R, A any](ma IO[A]) ReaderIOResult[R, A]

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

func RightReader

func RightReader[R, A any](ma Reader[R, A]) ReaderIOResult[R, A]

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

func RightReaderIO

func RightReaderIO[R, A any](ma ReaderIO[R, A]) ReaderIOResult[R, A]

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

func SequenceArray

func SequenceArray[R, A any](ma []ReaderIOResult[R, A]) ReaderIOResult[R, []A]

SequenceArray converts an array of ReaderIOResult into a ReaderIOResult 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 ReaderIOResult computations

Returns:

A ReaderIOResult that produces an array of results

Example:

computations := []ReaderIOResult[Config, error, int]{
    fetchCount("users"),
    fetchCount("posts"),
    fetchCount("comments"),
}
result := SequenceArray(computations)
// result(cfg)() returns Right([userCount, postCount, commentCount]) or Left(error)

func SequenceRecord

func SequenceRecord[K comparable, R, A any](ma map[K]ReaderIOResult[R, A]) ReaderIOResult[R, map[K]A]

SequenceRecord converts a map of ReaderIOResult into a ReaderIOResult 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 ReaderIOResult computations

Returns:

A ReaderIOResult that produces a map of results

Example:

computations := map[string]ReaderIOResult[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

func SequenceT1[R, A any](a ReaderIOResult[R, A]) ReaderIOResult[R, T.Tuple1[A]]

SequenceT1 converts a single ReaderIOResult into a ReaderIOResult 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, A, B any](a ReaderIOResult[R, A], b ReaderIOResult[R, B]) ReaderIOResult[R, T.Tuple2[A, B]]

SequenceT2 combines two ReaderIOResult computations into a single ReaderIOResult 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, A, B, C any](a ReaderIOResult[R, A], b ReaderIOResult[R, B], c ReaderIOResult[R, C]) ReaderIOResult[R, T.Tuple3[A, B, C]]

SequenceT3 combines three ReaderIOResult computations into a single ReaderIOResult 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, A, B, C, D any](a ReaderIOResult[R, A], b ReaderIOResult[R, B], c ReaderIOResult[R, C], d ReaderIOResult[R, D]) ReaderIOResult[R, T.Tuple4[A, B, C, D]]

SequenceT4 combines four ReaderIOResult computations into a single ReaderIOResult 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 ThrowError

func ThrowError[R, A any](e error) ReaderIOResult[R, A]

ThrowError creates a failed ReaderIOResult with the given error. This is an alias for Left, following the naming convention from other functional libraries.

func TryCatch

func TryCatch[R, A any](f func(R) func() (A, error), onThrow Endomorphism[error]) ReaderIOResult[R, A]

TryCatch wraps a function that returns (value, error) into a ReaderIOResult. The onThrow function converts the error into the desired error type.

type ReaderOption

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

ReaderOption represents a computation that depends on an environment R and may not produce a value.

type ReaderResult

type ReaderResult[R, A any] = readerresult.ReaderResult[R, A]

ReaderResult represents a computation that depends on an environment R and may fail with an error.

type Result

type Result[A any] = result.Result[A]

Result represents a computation that may fail with an error.

type Void added in v2.2.15

type Void = function.Void

Jump to

Keyboard shortcuts

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