readerioresult

package
v2.2.12 Latest Latest
Warning

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

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

Documentation

Overview

package readerioresult provides a specialized version of [readerioeither.ReaderIOResult] that uses context.Context as the context type and [error] as the left (error) type. This package is designed for typical Go applications where context-aware, effectful computations with error handling are needed.

Core Concept

ReaderIOResult[A] represents a computation that:

  • Depends on a context.Context (Reader aspect)
  • Performs side effects (IO aspect)
  • Can fail with an [error] (Either aspect)
  • Produces a value of type A on success

The type is defined as:

ReaderIOResult[A] = func(context.Context) func() Either[error, A]

This combines three powerful functional programming concepts:

  • Reader: Dependency injection via context
  • IO: Deferred side effects
  • Either: Explicit error handling

Key Features

  • Context-aware operations with automatic cancellation support
  • Parallel and sequential execution modes for applicative operations
  • Resource management with automatic cleanup (RAII pattern)
  • Thread-safe operations with lock management
  • Comprehensive error handling combinators
  • Conversion utilities for standard Go error-returning functions

Core Operations

Construction:

  • Of, Right: Create successful computations
  • Left: Create failed computations
  • FromEither, FromIO, FromIOEither: Convert from other types
  • TryCatch: Wrap error-returning functions
  • [Eitherize0-10]: Convert standard Go functions to ReaderIOResult

Transformation:

  • Map: Transform success values
  • [MapLeft]: Transform error values
  • [BiMap]: Transform both success and error values
  • Chain: Sequence dependent computations
  • ChainFirst: Sequence computations, keeping first result

Combination:

Error Handling:

  • Fold: Handle both success and error cases
  • GetOrElse: Provide default value on error
  • OrElse: Try alternative computation on error
  • Alt: Alternative computation with lazy evaluation

Context Operations:

  • Ask: Access the context
  • [Asks]: Access and transform the context
  • WithContext: Add context cancellation checks
  • Never: Create a computation that waits for context cancellation

Resource Management:

  • Bracket: Ensure resource cleanup (acquire/use/release pattern)
  • WithResource: Manage resource lifecycle with automatic cleanup
  • WithLock: Execute operations within lock scope

Timing:

  • Delay: Delay execution by duration
  • Timer: Return current time after delay

Usage Example

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

// Define a computation that reads from context and may fail
func fetchUser(id string) RIOE.ReaderIOResult[User] {
    return F.Pipe2(
        RIOE.Ask(),
        RIOE.Chain(func(ctx context.Context) RIOE.ReaderIOResult[User] {
            return RIOE.TryCatch(func(ctx context.Context) func() (User, error) {
                return func() (User, error) {
                    return userService.Get(ctx, id)
                }
            })
        }),
        RIOE.Map(func(user User) User {
            // Transform the user
            return user
        }),
    )
}

// Execute the computation
ctx := t.Context()
result := fetchUser("123")(ctx)()
// result is Either[error, User]

Parallel vs Sequential Execution

The package supports both parallel and sequential execution for applicative operations:

// Sequential execution (default for Ap)
result := RIOE.ApSeq(value)(function)

// Parallel execution with automatic cancellation
result := RIOE.ApPar(value)(function)

When using parallel execution, if any operation fails, all other operations are automatically cancelled via context cancellation.

Resource Management Example

// Automatic resource cleanup with WithResource
result := F.Pipe1(
    RIOE.WithResource(
        openFile("data.txt"),
        closeFile,
    ),
    func(use func(func(*os.File) RIOE.ReaderIOResult[string]) RIOE.ReaderIOResult[string]) RIOE.ReaderIOResult[string] {
        return use(func(file *os.File) RIOE.ReaderIOResult[string] {
            return readContent(file)
        })
    },
)

Bind Operations

The package provides do-notation style operations for building complex computations:

result := F.Pipe3(
    RIOE.Do(State{}),
    RIOE.Bind(setState, getFirstValue),
    RIOE.Bind(setState2, getSecondValue),
    RIOE.Map(finalTransform),
)

Context Cancellation

All operations respect context cancellation. When a context is cancelled, operations will return an error containing the cancellation cause:

ctx, cancel := context.WithCancelCause(t.Context())
cancel(errors.New("operation cancelled"))
result := computation(ctx)() // Returns Left with cancellation error

Package readerioresult provides logging utilities for ReaderIOResult computations. It includes functions for entry/exit logging with timing, correlation IDs, and context management.

Example (SequenceReaderResult_errorHandling)

Example_sequenceReaderResult_errorHandling demonstrates how SequenceReaderResult enables point-free style with proper error handling at multiple levels.

package main

import (
	"context"
	"fmt"

	RIOE "github.com/IBM/fp-go/v2/context/readerioresult"
	"github.com/IBM/fp-go/v2/either"

	F "github.com/IBM/fp-go/v2/function"

	N "github.com/IBM/fp-go/v2/number"
)

func main() {
	type ValidationConfig struct {
		MinValue int
		MaxValue int
	}

	// A computation that can fail at both outer and inner levels
	makeValidator := func(ctx context.Context) func() either.Either[error, func(context.Context) either.Either[error, int]] {
		return func() either.Either[error, func(context.Context) either.Either[error, int]] {
			// Outer level: check context
			if ctx.Err() != nil {
				return either.Left[func(context.Context) either.Either[error, int]](ctx.Err())
			}

			// Return inner computation
			return either.Right[error](func(innerCtx context.Context) either.Either[error, int] {
				// Inner level: perform validation
				value := 42
				if value < 0 {
					return either.Left[int](fmt.Errorf("value too small: %d", value))
				}
				if value > 100 {
					return either.Left[int](fmt.Errorf("value too large: %d", value))
				}
				return either.Right[error](value)
			})
		}
	}

	// Sequence to enable point-free composition
	sequenced := RIOE.SequenceReaderResult(makeValidator)

	// Build a pipeline with error handling
	ctx := context.Background()
	pipeline := F.Pipe2(
		sequenced(ctx),
		RIOE.Map(N.Mul(2)),
		RIOE.Chain(func(x int) RIOE.ReaderIOResult[string] {
			return RIOE.Of(fmt.Sprintf("Result: %d", x))
		}),
	)

	result := pipeline(ctx)()

	if value, err := either.Unwrap(result); err == nil {
		fmt.Println(value)
	}
}
Output:

Result: 84
Example (SequenceReader_basicUsage)

Example_sequenceReader_basicUsage demonstrates the basic usage of SequenceReader to flip the parameter order, enabling point-free style programming.

package main

import (
	"context"
	"fmt"

	RIOE "github.com/IBM/fp-go/v2/context/readerioresult"
	"github.com/IBM/fp-go/v2/either"
)

func main() {
	type Config struct {
		Multiplier int
	}

	// A computation that produces a Reader based on context
	getComputation := func(ctx context.Context) func() either.Either[error, func(Config) int] {
		return func() either.Either[error, func(Config) int] {
			// This could check context for cancellation, deadlines, etc.
			return either.Right[error](func(cfg Config) int {
				return cfg.Multiplier * 10
			})
		}
	}

	// Sequence it to flip the parameter order
	// Now Config comes first, then context
	sequenced := RIOE.SequenceReader(getComputation)

	// Partially apply the Config - this is the key benefit for point-free style
	cfg := Config{Multiplier: 5}
	withConfig := sequenced(cfg)

	// Now we have a ReaderIOResult[int] that can be used with any context
	ctx := context.Background()
	result := withConfig(ctx)()

	if value, err := either.Unwrap(result); err == nil {
		fmt.Println(value)
	}
}
Output:

50
Example (SequenceReader_dependencyInjection)

Example_sequenceReader_dependencyInjection demonstrates how SequenceReader enables clean dependency injection patterns in point-free style.

package main

import (
	"context"
	"fmt"

	RIOE "github.com/IBM/fp-go/v2/context/readerioresult"
	"github.com/IBM/fp-go/v2/either"
)

func main() {
	// Define our dependencies
	type Database struct {
		ConnectionString string
	}

	type UserService struct {
		db Database
	}

	// A function that creates a computation requiring a Database
	makeQuery := func(ctx context.Context) func() either.Either[error, func(Database) string] {
		return func() either.Either[error, func(Database) string] {
			return either.Right[error](func(db Database) string {
				return fmt.Sprintf("Querying %s", db.ConnectionString)
			})
		}
	}

	// Sequence to enable dependency injection
	queryWithDB := RIOE.SequenceReader(makeQuery)

	// Inject the database dependency
	db := Database{ConnectionString: "localhost:5432"}
	query := queryWithDB(db)

	// Execute with context
	ctx := context.Background()
	result := query(ctx)()

	if value, err := either.Unwrap(result); err == nil {
		fmt.Println(value)
	}
}
Output:

Querying localhost:5432
Example (SequenceReader_multipleEnvironments)

Example_sequenceReader_multipleEnvironments demonstrates using SequenceReader to work with multiple environment types in a clean, composable way.

package main

import (
	"context"
	"fmt"

	RIOE "github.com/IBM/fp-go/v2/context/readerioresult"
	"github.com/IBM/fp-go/v2/either"
)

func main() {
	type DatabaseConfig struct {
		Host string
		Port int
	}

	type APIConfig struct {
		Endpoint string
		APIKey   string
	}

	// Function that needs DatabaseConfig
	getDatabaseURL := func(ctx context.Context) func() either.Either[error, func(DatabaseConfig) string] {
		return func() either.Either[error, func(DatabaseConfig) string] {
			return either.Right[error](func(cfg DatabaseConfig) string {
				return fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)
			})
		}
	}

	// Function that needs APIConfig
	getAPIURL := func(ctx context.Context) func() either.Either[error, func(APIConfig) string] {
		return func() either.Either[error, func(APIConfig) string] {
			return either.Right[error](func(cfg APIConfig) string {
				return cfg.Endpoint
			})
		}
	}

	// Sequence both to enable partial application
	withDBConfig := RIOE.SequenceReader(getDatabaseURL)
	withAPIConfig := RIOE.SequenceReader(getAPIURL)

	// Partially apply different configs
	dbCfg := DatabaseConfig{Host: "localhost", Port: 5432}
	apiCfg := APIConfig{Endpoint: "https://api.example.com", APIKey: "secret"}

	dbQuery := withDBConfig(dbCfg)
	apiQuery := withAPIConfig(apiCfg)

	// Execute both with the same context
	ctx := context.Background()

	dbResult := dbQuery(ctx)()
	apiResult := apiQuery(ctx)()

	if dbURL, err := either.Unwrap(dbResult); err == nil {
		fmt.Println("Database:", dbURL)
	}
	if apiURL, err := either.Unwrap(apiResult); err == nil {
		fmt.Println("API:", apiURL)
	}
}
Output:

Database: localhost:5432
API: https://api.example.com
Example (SequenceReader_partialApplication)

Example_sequenceReader_partialApplication demonstrates the power of partial application enabled by SequenceReader for building reusable computations.

package main

import (
	"context"
	"fmt"

	RIOE "github.com/IBM/fp-go/v2/context/readerioresult"
	"github.com/IBM/fp-go/v2/either"
)

func main() {
	type ServiceConfig struct {
		ServiceName string
		Version     string
	}

	// Create a computation factory
	makeServiceInfo := func(ctx context.Context) func() either.Either[error, func(ServiceConfig) string] {
		return func() either.Either[error, func(ServiceConfig) string] {
			return either.Right[error](func(cfg ServiceConfig) string {
				return fmt.Sprintf("%s v%s", cfg.ServiceName, cfg.Version)
			})
		}
	}

	// Sequence it
	sequenced := RIOE.SequenceReader(makeServiceInfo)

	// Create multiple service configurations
	authConfig := ServiceConfig{ServiceName: "AuthService", Version: "1.0.0"}
	userConfig := ServiceConfig{ServiceName: "UserService", Version: "2.1.0"}

	// Partially apply each config to create specialized computations
	getAuthInfo := sequenced(authConfig)
	getUserInfo := sequenced(userConfig)

	// These can now be reused across different contexts
	ctx := context.Background()

	authResult := getAuthInfo(ctx)()
	userResult := getUserInfo(ctx)()

	if auth, err := either.Unwrap(authResult); err == nil {
		fmt.Println(auth)
	}
	if user, err := either.Unwrap(userResult); err == nil {
		fmt.Println(user)
	}
}
Output:

AuthService v1.0.0
UserService v2.1.0
Example (SequenceReader_pointFreeComposition)

Example_sequenceReader_pointFreeComposition demonstrates how SequenceReader enables point-free style composition of computations.

package main

import (
	"context"
	"fmt"

	RIOE "github.com/IBM/fp-go/v2/context/readerioresult"
	"github.com/IBM/fp-go/v2/either"

	F "github.com/IBM/fp-go/v2/function"
)

func main() {
	type Config struct {
		BaseValue int
	}

	// Step 1: Create a computation that produces a Reader
	step1 := func(ctx context.Context) func() either.Either[error, func(Config) int] {
		return func() either.Either[error, func(Config) int] {
			return either.Right[error](func(cfg Config) int {
				return cfg.BaseValue * 2
			})
		}
	}

	// Step 2: Sequence it to enable partial application
	sequenced := RIOE.SequenceReader(step1)

	// Step 3: Build a pipeline using point-free style
	// Partially apply the config
	cfg := Config{BaseValue: 10}

	// Create a reusable computation with the config baked in
	computation := F.Pipe1(
		sequenced(cfg),
		RIOE.Map(func(x int) int { return x + 5 }),
	)

	// Execute the pipeline
	ctx := context.Background()
	result := computation(ctx)()

	if value, err := either.Unwrap(result); err == nil {
		fmt.Println(value)
	}
}
Output:

25
Example (SequenceReader_testingBenefits)

Example_sequenceReader_testingBenefits demonstrates how SequenceReader makes testing easier by allowing you to inject test dependencies.

package main

import (
	"context"
	"fmt"

	RIOE "github.com/IBM/fp-go/v2/context/readerioresult"
	"github.com/IBM/fp-go/v2/either"
)

func main() {
	// Simple logger that collects messages
	type SimpleLogger struct {
		Messages []string
	}

	// A computation that depends on a logger (using the struct directly)
	makeLoggingOperation := func(ctx context.Context) func() either.Either[error, func(*SimpleLogger) string] {
		return func() either.Either[error, func(*SimpleLogger) string] {
			return either.Right[error](func(logger *SimpleLogger) string {
				logger.Messages = append(logger.Messages, "Operation started")
				result := "Success"
				logger.Messages = append(logger.Messages, fmt.Sprintf("Operation completed: %s", result))
				return result
			})
		}
	}

	// Sequence to enable dependency injection
	sequenced := RIOE.SequenceReader(makeLoggingOperation)

	// Inject a test logger
	testLogger := &SimpleLogger{Messages: []string{}}
	operation := sequenced(testLogger)

	// Execute
	ctx := context.Background()
	result := operation(ctx)()

	if value, err := either.Unwrap(result); err == nil {
		fmt.Println("Result:", value)
		fmt.Println("Logs:", len(testLogger.Messages))
	}
}
Output:

Result: Success
Logs: 2

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ChainFirstReaderOptionK

func ChainFirstReaderOptionK[A, B any](onNone func() error) func(readeroption.Kleisli[context.Context, A, B]) Operator[A, A]

func ChainOptionK

func ChainOptionK[A, B any](onNone func() error) func(option.Kleisli[A, B]) Operator[A, B]

ChainOptionK chains a function that returns an Option into a ReaderIOResult computation. If the Option is None, the provided error function is called.

Parameters:

  • onNone: Function to generate an error when Option is None

Returns a function that chains Option-returning functions into ReaderIOResult.

func ChainReaderOptionK

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

func Eitherize0

func Eitherize0[F ~func(context.Context) (R, error), R any](f F) func() ReaderIOResult[R]

Eitherize0 converts a function with 0 parameters returning a tuple into a function with 0 parameters returning a [ReaderIOResult[R]] The inverse function is Uneitherize0

func Eitherize10

func Eitherize10[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) ReaderIOResult[R]

Eitherize10 converts a function with 10 parameters returning a tuple into a function with 10 parameters returning a [ReaderIOResult[R]] The inverse function is Uneitherize10

func Eitherize2

func Eitherize2[F ~func(context.Context, T0, T1) (R, error), T0, T1, R any](f F) func(T0, T1) ReaderIOResult[R]

Eitherize2 converts a function with 2 parameters returning a tuple into a function with 2 parameters returning a [ReaderIOResult[R]] The inverse function is Uneitherize2

func Eitherize3

func Eitherize3[F ~func(context.Context, T0, T1, T2) (R, error), T0, T1, T2, R any](f F) func(T0, T1, T2) ReaderIOResult[R]

Eitherize3 converts a function with 3 parameters returning a tuple into a function with 3 parameters returning a [ReaderIOResult[R]] The inverse function is Uneitherize3

func Eitherize4

func Eitherize4[F ~func(context.Context, T0, T1, T2, T3) (R, error), T0, T1, T2, T3, R any](f F) func(T0, T1, T2, T3) ReaderIOResult[R]

Eitherize4 converts a function with 4 parameters returning a tuple into a function with 4 parameters returning a [ReaderIOResult[R]] The inverse function is Uneitherize4

func Eitherize5

func Eitherize5[F ~func(context.Context, T0, T1, T2, T3, T4) (R, error), T0, T1, T2, T3, T4, R any](f F) func(T0, T1, T2, T3, T4) ReaderIOResult[R]

Eitherize5 converts a function with 5 parameters returning a tuple into a function with 5 parameters returning a [ReaderIOResult[R]] The inverse function is Uneitherize5

func Eitherize6

func Eitherize6[F ~func(context.Context, T0, T1, T2, T3, T4, T5) (R, error), T0, T1, T2, T3, T4, T5, R any](f F) func(T0, T1, T2, T3, T4, T5) ReaderIOResult[R]

Eitherize6 converts a function with 6 parameters returning a tuple into a function with 6 parameters returning a [ReaderIOResult[R]] The inverse function is Uneitherize6

func Eitherize7

func Eitherize7[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6) (R, error), T0, T1, T2, T3, T4, T5, T6, R any](f F) func(T0, T1, T2, T3, T4, T5, T6) ReaderIOResult[R]

Eitherize7 converts a function with 7 parameters returning a tuple into a function with 7 parameters returning a [ReaderIOResult[R]] The inverse function is Uneitherize7

func Eitherize8

func Eitherize8[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7) ReaderIOResult[R]

Eitherize8 converts a function with 8 parameters returning a tuple into a function with 8 parameters returning a [ReaderIOResult[R]] The inverse function is Uneitherize8

func Eitherize9

func Eitherize9[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8) ReaderIOResult[R]

Eitherize9 converts a function with 9 parameters returning a tuple into a function with 9 parameters returning a [ReaderIOResult[R]] The inverse function is Uneitherize9

func Eq

func Eq[A any](eq eq.Eq[Either[A]]) func(context.Context) eq.Eq[ReaderIOResult[A]]

Eq implements the equals predicate for values contained in the ReaderIOResult monad. It creates an equality checker that can compare two ReaderIOResult values by executing them with a given context and comparing their results using the provided Either equality checker.

Parameters:

  • eq: Equality checker for Either[A] values

Returns a function that takes a context and returns an equality checker for ReaderIOResult[A].

Example:

eqInt := eq.FromEquals(func(a, b either.Either[error, int]) bool {
    return either.Eq(eq.FromEquals(func(x, y int) bool { return x == y }))(a, b)
})
eqRIE := Eq(eqInt)
ctx := t.Context()
equal := eqRIE(ctx).Equals(Right[int](42), Right[int](42)) // true

func GetOrElse

func GetOrElse[A any](onLeft readerio.Kleisli[error, A]) func(ReaderIOResult[A]) ReaderIO[A]

GetOrElse extracts the value from a ReaderIOResult, providing a default via a function if it fails. The result is a ReaderIO that always succeeds.

Parameters:

  • onLeft: Function to provide a default value from the error

Returns a function that converts a ReaderIOResult to a ReaderIO.

func Read

func Read[A any](r context.Context) func(ReaderIOResult[A]) IOResult[A]

func ReadIO added in v2.1.10

func ReadIO[A any](r IO[context.Context]) func(ReaderIOResult[A]) IOResult[A]

func ReadIOEither added in v2.1.10

func ReadIOEither[A any](r IOResult[context.Context]) func(ReaderIOResult[A]) IOResult[A]

func ReadIOResult added in v2.1.10

func ReadIOResult[A any](r IOResult[context.Context]) func(ReaderIOResult[A]) IOResult[A]

func TapReaderOptionK

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

func TraverseParTuple10

func TraverseParTuple10[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], F6 ~func(A6) ReaderIOResult[T6], F7 ~func(A7) ReaderIOResult[T7], F8 ~func(A8) ReaderIOResult[T8], F9 ~func(A9) ReaderIOResult[T9], F10 ~func(A10) ReaderIOResult[T10], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) func(tuple.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]) ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]

TraverseParTuple10 converts a [tuple.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]] into a [ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]

func TraverseParTuple2

func TraverseParTuple2[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], T1, T2, A1, A2 any](f1 F1, f2 F2) func(tuple.Tuple2[A1, A2]) ReaderIOResult[tuple.Tuple2[T1, T2]]

TraverseParTuple2 converts a [tuple.Tuple2[A1, A2]] into a [ReaderIOResult[tuple.Tuple2[T1, T2]]]

func TraverseParTuple3

func TraverseParTuple3[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], T1, T2, T3, A1, A2, A3 any](f1 F1, f2 F2, f3 F3) func(tuple.Tuple3[A1, A2, A3]) ReaderIOResult[tuple.Tuple3[T1, T2, T3]]

TraverseParTuple3 converts a [tuple.Tuple3[A1, A2, A3]] into a [ReaderIOResult[tuple.Tuple3[T1, T2, T3]]]

func TraverseParTuple4

func TraverseParTuple4[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], T1, T2, T3, T4, A1, A2, A3, A4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(tuple.Tuple4[A1, A2, A3, A4]) ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]

TraverseParTuple4 converts a [tuple.Tuple4[A1, A2, A3, A4]] into a [ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]]

func TraverseParTuple5

func TraverseParTuple5[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], T1, T2, T3, T4, T5, A1, A2, A3, A4, A5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(tuple.Tuple5[A1, A2, A3, A4, A5]) ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]

TraverseParTuple5 converts a [tuple.Tuple5[A1, A2, A3, A4, A5]] into a [ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]]

func TraverseParTuple6

func TraverseParTuple6[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], F6 ~func(A6) ReaderIOResult[T6], T1, T2, T3, T4, T5, T6, A1, A2, A3, A4, A5, A6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(tuple.Tuple6[A1, A2, A3, A4, A5, A6]) ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]

TraverseParTuple6 converts a [tuple.Tuple6[A1, A2, A3, A4, A5, A6]] into a [ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]

func TraverseParTuple7

func TraverseParTuple7[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], F6 ~func(A6) ReaderIOResult[T6], F7 ~func(A7) ReaderIOResult[T7], T1, T2, T3, T4, T5, T6, T7, A1, A2, A3, A4, A5, A6, A7 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) func(tuple.Tuple7[A1, A2, A3, A4, A5, A6, A7]) ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]

TraverseParTuple7 converts a [tuple.Tuple7[A1, A2, A3, A4, A5, A6, A7]] into a [ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]

func TraverseParTuple8

func TraverseParTuple8[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], F6 ~func(A6) ReaderIOResult[T6], F7 ~func(A7) ReaderIOResult[T7], F8 ~func(A8) ReaderIOResult[T8], T1, T2, T3, T4, T5, T6, T7, T8, A1, A2, A3, A4, A5, A6, A7, A8 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) func(tuple.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]) ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]

TraverseParTuple8 converts a [tuple.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]] into a [ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]

func TraverseParTuple9

func TraverseParTuple9[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], F6 ~func(A6) ReaderIOResult[T6], F7 ~func(A7) ReaderIOResult[T7], F8 ~func(A8) ReaderIOResult[T8], F9 ~func(A9) ReaderIOResult[T9], T1, T2, T3, T4, T5, T6, T7, T8, T9, A1, A2, A3, A4, A5, A6, A7, A8, A9 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) func(tuple.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]) ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]

TraverseParTuple9 converts a [tuple.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]] into a [ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]

func TraverseReader

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

TraverseReader transforms a ReaderIOResult computation by applying a Reader-based function, effectively introducing a new environment dependency.

This function takes a Reader-based transformation (Kleisli arrow) and returns a function that can transform a ReaderIOResult. The result allows you to provide the Reader's environment (R) first, which then produces a ReaderIOResult that depends on the context.

Type transformation:

From: ReaderIOResult[A]
      = func(context.Context) func() Either[error, A]

With: reader.Kleisli[R, A, B]
      = func(A) func(R) B

To:   func(ReaderIOResult[A]) func(R) ReaderIOResult[B]
      = func(ReaderIOResult[A]) func(R) func(context.Context) func() Either[error, B]

This enables:

  1. Transforming values within a ReaderIOResult using environment-dependent logic
  2. Introducing new environment dependencies into existing computations
  3. Building composable pipelines where transformations depend on configuration or dependencies
  4. Point-free style composition with Reader-based transformations

Type Parameters:

  • R: The environment type that the Reader depends on
  • A: The input value type
  • B: The output value type

Parameters:

  • f: A Reader-based Kleisli arrow that transforms A to B using environment R

Returns:

  • A function that takes a ReaderIOResult[A] and returns a Kleisli[R, B], which is func(R) ReaderIOResult[B]

The function preserves error handling and IO effects while adding the Reader environment dependency.

Example:

type Config struct {
    Multiplier int
}

// A Reader-based transformation that depends on Config
multiply := func(x int) func(Config) int {
    return func(cfg Config) int {
        return x * cfg.Multiplier
    }
}

// Original computation that produces an int
computation := Right[int](10)

// Apply TraverseReader to introduce Config dependency
traversed := TraverseReader[Config, int, int](multiply)
result := traversed(computation)

// Now we can provide the Config to get the final result
cfg := Config{Multiplier: 5}
ctx := t.Context()
finalResult := result(cfg)(ctx)() // Returns Right(50)

In point-free style, this enables clean composition:

var pipeline = F.Flow3(
    loadValue,                    // ReaderIOResult[int]
    TraverseReader(multiplyByConfig), // func(Config) ReaderIOResult[int]
    applyConfig(cfg),             // ReaderIOResult[int]
)

func TraverseSeqTuple10

func TraverseSeqTuple10[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], F6 ~func(A6) ReaderIOResult[T6], F7 ~func(A7) ReaderIOResult[T7], F8 ~func(A8) ReaderIOResult[T8], F9 ~func(A9) ReaderIOResult[T9], F10 ~func(A10) ReaderIOResult[T10], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) func(tuple.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]) ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]

TraverseSeqTuple10 converts a [tuple.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]] into a [ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]

func TraverseSeqTuple2

func TraverseSeqTuple2[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], T1, T2, A1, A2 any](f1 F1, f2 F2) func(tuple.Tuple2[A1, A2]) ReaderIOResult[tuple.Tuple2[T1, T2]]

TraverseSeqTuple2 converts a [tuple.Tuple2[A1, A2]] into a [ReaderIOResult[tuple.Tuple2[T1, T2]]]

func TraverseSeqTuple3

func TraverseSeqTuple3[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], T1, T2, T3, A1, A2, A3 any](f1 F1, f2 F2, f3 F3) func(tuple.Tuple3[A1, A2, A3]) ReaderIOResult[tuple.Tuple3[T1, T2, T3]]

TraverseSeqTuple3 converts a [tuple.Tuple3[A1, A2, A3]] into a [ReaderIOResult[tuple.Tuple3[T1, T2, T3]]]

func TraverseSeqTuple4

func TraverseSeqTuple4[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], T1, T2, T3, T4, A1, A2, A3, A4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(tuple.Tuple4[A1, A2, A3, A4]) ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]

TraverseSeqTuple4 converts a [tuple.Tuple4[A1, A2, A3, A4]] into a [ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]]

func TraverseSeqTuple5

func TraverseSeqTuple5[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], T1, T2, T3, T4, T5, A1, A2, A3, A4, A5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(tuple.Tuple5[A1, A2, A3, A4, A5]) ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]

TraverseSeqTuple5 converts a [tuple.Tuple5[A1, A2, A3, A4, A5]] into a [ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]]

func TraverseSeqTuple6

func TraverseSeqTuple6[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], F6 ~func(A6) ReaderIOResult[T6], T1, T2, T3, T4, T5, T6, A1, A2, A3, A4, A5, A6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(tuple.Tuple6[A1, A2, A3, A4, A5, A6]) ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]

TraverseSeqTuple6 converts a [tuple.Tuple6[A1, A2, A3, A4, A5, A6]] into a [ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]

func TraverseSeqTuple7

func TraverseSeqTuple7[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], F6 ~func(A6) ReaderIOResult[T6], F7 ~func(A7) ReaderIOResult[T7], T1, T2, T3, T4, T5, T6, T7, A1, A2, A3, A4, A5, A6, A7 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) func(tuple.Tuple7[A1, A2, A3, A4, A5, A6, A7]) ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]

TraverseSeqTuple7 converts a [tuple.Tuple7[A1, A2, A3, A4, A5, A6, A7]] into a [ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]

func TraverseSeqTuple8

func TraverseSeqTuple8[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], F6 ~func(A6) ReaderIOResult[T6], F7 ~func(A7) ReaderIOResult[T7], F8 ~func(A8) ReaderIOResult[T8], T1, T2, T3, T4, T5, T6, T7, T8, A1, A2, A3, A4, A5, A6, A7, A8 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) func(tuple.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]) ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]

TraverseSeqTuple8 converts a [tuple.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]] into a [ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]

func TraverseSeqTuple9

func TraverseSeqTuple9[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], F6 ~func(A6) ReaderIOResult[T6], F7 ~func(A7) ReaderIOResult[T7], F8 ~func(A8) ReaderIOResult[T8], F9 ~func(A9) ReaderIOResult[T9], T1, T2, T3, T4, T5, T6, T7, T8, T9, A1, A2, A3, A4, A5, A6, A7, A8, A9 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) func(tuple.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]) ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]

TraverseSeqTuple9 converts a [tuple.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]] into a [ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]

func TraverseTuple10

func TraverseTuple10[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], F6 ~func(A6) ReaderIOResult[T6], F7 ~func(A7) ReaderIOResult[T7], F8 ~func(A8) ReaderIOResult[T8], F9 ~func(A9) ReaderIOResult[T9], F10 ~func(A10) ReaderIOResult[T10], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) func(tuple.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]) ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]

TraverseTuple10 converts a [tuple.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]] into a [ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]

func TraverseTuple2

func TraverseTuple2[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], T1, T2, A1, A2 any](f1 F1, f2 F2) func(tuple.Tuple2[A1, A2]) ReaderIOResult[tuple.Tuple2[T1, T2]]

TraverseTuple2 converts a [tuple.Tuple2[A1, A2]] into a [ReaderIOResult[tuple.Tuple2[T1, T2]]]

func TraverseTuple3

func TraverseTuple3[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], T1, T2, T3, A1, A2, A3 any](f1 F1, f2 F2, f3 F3) func(tuple.Tuple3[A1, A2, A3]) ReaderIOResult[tuple.Tuple3[T1, T2, T3]]

TraverseTuple3 converts a [tuple.Tuple3[A1, A2, A3]] into a [ReaderIOResult[tuple.Tuple3[T1, T2, T3]]]

func TraverseTuple4

func TraverseTuple4[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], T1, T2, T3, T4, A1, A2, A3, A4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(tuple.Tuple4[A1, A2, A3, A4]) ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]

TraverseTuple4 converts a [tuple.Tuple4[A1, A2, A3, A4]] into a [ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]]

func TraverseTuple5

func TraverseTuple5[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], T1, T2, T3, T4, T5, A1, A2, A3, A4, A5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(tuple.Tuple5[A1, A2, A3, A4, A5]) ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]

TraverseTuple5 converts a [tuple.Tuple5[A1, A2, A3, A4, A5]] into a [ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]]

func TraverseTuple6

func TraverseTuple6[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], F6 ~func(A6) ReaderIOResult[T6], T1, T2, T3, T4, T5, T6, A1, A2, A3, A4, A5, A6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(tuple.Tuple6[A1, A2, A3, A4, A5, A6]) ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]

TraverseTuple6 converts a [tuple.Tuple6[A1, A2, A3, A4, A5, A6]] into a [ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]

func TraverseTuple7

func TraverseTuple7[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], F6 ~func(A6) ReaderIOResult[T6], F7 ~func(A7) ReaderIOResult[T7], T1, T2, T3, T4, T5, T6, T7, A1, A2, A3, A4, A5, A6, A7 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) func(tuple.Tuple7[A1, A2, A3, A4, A5, A6, A7]) ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]

TraverseTuple7 converts a [tuple.Tuple7[A1, A2, A3, A4, A5, A6, A7]] into a [ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]

func TraverseTuple8

func TraverseTuple8[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], F6 ~func(A6) ReaderIOResult[T6], F7 ~func(A7) ReaderIOResult[T7], F8 ~func(A8) ReaderIOResult[T8], T1, T2, T3, T4, T5, T6, T7, T8, A1, A2, A3, A4, A5, A6, A7, A8 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) func(tuple.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]) ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]

TraverseTuple8 converts a [tuple.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]] into a [ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]

func TraverseTuple9

func TraverseTuple9[F1 ~func(A1) ReaderIOResult[T1], F2 ~func(A2) ReaderIOResult[T2], F3 ~func(A3) ReaderIOResult[T3], F4 ~func(A4) ReaderIOResult[T4], F5 ~func(A5) ReaderIOResult[T5], F6 ~func(A6) ReaderIOResult[T6], F7 ~func(A7) ReaderIOResult[T7], F8 ~func(A8) ReaderIOResult[T8], F9 ~func(A9) ReaderIOResult[T9], T1, T2, T3, T4, T5, T6, T7, T8, T9, A1, A2, A3, A4, A5, A6, A7, A8, A9 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) func(tuple.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]) ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]

TraverseTuple9 converts a [tuple.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]] into a [ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]

func Uneitherize0

func Uneitherize0[F ~func() ReaderIOResult[R], R any](f F) func(context.Context) (R, error)

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

func Uneitherize1

func Uneitherize1[F ~func(T0) ReaderIOResult[R], T0, R any](f F) func(context.Context, T0) (R, error)

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

func Uneitherize10

func Uneitherize10[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) ReaderIOResult[R], T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R any](f F) func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error)

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

func Uneitherize2

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

Uneitherize2 converts a function with 3 parameters returning a [ReaderIOResult[R]] into a function with 2 parameters returning a tuple. The first parameter is considered to be the context.Context.

func Uneitherize3

func Uneitherize3[F ~func(T0, T1, T2) ReaderIOResult[R], T0, T1, T2, R any](f F) func(context.Context, T0, T1, T2) (R, error)

Uneitherize3 converts a function with 4 parameters returning a [ReaderIOResult[R]] into a function with 3 parameters returning a tuple. The first parameter is considered to be the context.Context.

func Uneitherize4

func Uneitherize4[F ~func(T0, T1, T2, T3) ReaderIOResult[R], T0, T1, T2, T3, R any](f F) func(context.Context, T0, T1, T2, T3) (R, error)

Uneitherize4 converts a function with 5 parameters returning a [ReaderIOResult[R]] into a function with 4 parameters returning a tuple. The first parameter is considered to be the context.Context.

func Uneitherize5

func Uneitherize5[F ~func(T0, T1, T2, T3, T4) ReaderIOResult[R], T0, T1, T2, T3, T4, R any](f F) func(context.Context, T0, T1, T2, T3, T4) (R, error)

Uneitherize5 converts a function with 6 parameters returning a [ReaderIOResult[R]] into a function with 5 parameters returning a tuple. The first parameter is considered to be the context.Context.

func Uneitherize6

func Uneitherize6[F ~func(T0, T1, T2, T3, T4, T5) ReaderIOResult[R], T0, T1, T2, T3, T4, T5, R any](f F) func(context.Context, T0, T1, T2, T3, T4, T5) (R, error)

Uneitherize6 converts a function with 7 parameters returning a [ReaderIOResult[R]] into a function with 6 parameters returning a tuple. The first parameter is considered to be the context.Context.

func Uneitherize7

func Uneitherize7[F ~func(T0, T1, T2, T3, T4, T5, T6) ReaderIOResult[R], T0, T1, T2, T3, T4, T5, T6, R any](f F) func(context.Context, T0, T1, T2, T3, T4, T5, T6) (R, error)

Uneitherize7 converts a function with 8 parameters returning a [ReaderIOResult[R]] into a function with 7 parameters returning a tuple. The first parameter is considered to be the context.Context.

func Uneitherize8

func Uneitherize8[F ~func(T0, T1, T2, T3, T4, T5, T6, T7) ReaderIOResult[R], T0, T1, T2, T3, T4, T5, T6, T7, R any](f F) func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7) (R, error)

Uneitherize8 converts a function with 9 parameters returning a [ReaderIOResult[R]] into a function with 8 parameters returning a tuple. The first parameter is considered to be the context.Context.

func Uneitherize9

func Uneitherize9[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8) ReaderIOResult[R], T0, T1, T2, T3, T4, T5, T6, T7, T8, R any](f F) func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error)

Uneitherize9 converts a function with 10 parameters returning a [ReaderIOResult[R]] into a function with 9 parameters returning a tuple. The first parameter is considered to be the context.Context.

Types

type CircuitBreaker added in v2.1.1

type CircuitBreaker[T any] = State[Env[T], ReaderIOResult[T]]

func MakeCircuitBreaker added in v2.1.1

func MakeCircuitBreaker[T any](
	currentTime IO[time.Time],
	closedState ClosedState,
	checkError option.Kleisli[error, error],
	policy retry.RetryPolicy,
	metrics circuitbreaker.Metrics,
) CircuitBreaker[T]

type ClosedState added in v2.1.1

type ClosedState = circuitbreaker.ClosedState

type Consumer

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

type Either

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

Either represents a computation that can result in either an error or a success value. This is specialized to use [error] as the left (error) type, which is the standard error type in Go.

Either[A] is equivalent to Either[error, A] from the either package.

type Endomorphism

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

type Env added in v2.1.1

type Env[T any] = Pair[IORef[circuitbreaker.BreakerState], ReaderIOResult[T]]

type IO

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

IO represents a side-effectful computation that produces a value of type A. The computation is deferred and only executed when invoked.

IO[A] is equivalent to func() A

type IOEither

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

IOEither represents a side-effectful computation that can fail with an error. This combines IO (side effects) with Either (error handling).

IOEither[A] is equivalent to func() Either[error, A]

type IORef added in v2.1.1

type IORef[A any] = ioref.IORef[A]

type IOResult

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

type Kleisli

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

func Eitherize1

func Eitherize1[F ~func(context.Context, T0) (R, error), T0, R any](f F) Kleisli[T0, R]

Eitherize1 converts a function with 1 parameters returning a tuple into a function with 1 parameters returning a [ReaderIOResult[R]] The inverse function is Uneitherize1

func FromPredicate

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

FromPredicate creates a ReaderIOResult from a predicate function. If the predicate returns true, the value is wrapped in Right; otherwise, Left with the error from onFalse.

Parameters:

  • pred: Predicate function to test the value
  • onFalse: Function to generate an error when predicate fails

Returns a function that converts a value to ReaderIOResult based on the predicate.

func FromReaderOption

func FromReaderOption[A any](onNone func() error) Kleisli[ReaderOption[context.Context, A], A]

func SLog

func SLog[A any](message string) Kleisli[Result[A], A]

SLog creates a Kleisli arrow that logs a Result value (success or error) with a message.

This function logs both successful values and errors at Info level using the logger from the context. It's a convenience wrapper around SLogWithCallback with standard settings.

The logged output includes:

  • For success: The message with the value as a structured "value" attribute
  • For error: The message with the error as a structured "error" attribute

The Result is passed through unchanged after logging, making this function transparent in the computation pipeline.

Type Parameters:

  • A: The success type of the Result

Parameters:

  • message: A descriptive message to include in the log entry

Returns:

  • A Kleisli arrow that logs the Result (value or error) and returns it unchanged

Example with successful Result:

pipeline := F.Pipe2(
    fetchUser(123),
    Chain(SLog[User]("Fetched user")),
    Map(func(u User) string { return u.Name }),
)

result := pipeline(t.Context())()
// If successful, logs: "Fetched user" value={ID:123 Name:"Alice"}
// If error, logs: "Fetched user" error="user not found"

Example in error handling pipeline:

pipeline := F.Pipe3(
    fetchData(id),
    Chain(SLog[Data]("Data fetched")),
    Chain(validateData),
    Chain(SLog[Data]("Data validated")),
    Chain(processData),
)

// Logs each step, including errors:
// "Data fetched" value={...} or error="..."
// "Data validated" value={...} or error="..."

Use Cases:

  • Debugging: Track both successful and failed Results in a pipeline
  • Error monitoring: Log errors as they occur in the computation
  • Flow tracking: See the progression of Results through a pipeline
  • Troubleshooting: Identify where errors are introduced or propagated

Note: This function logs the Result itself (which may contain an error), not just successful values. For logging only successful values, use TapSLog instead.

func SLogWithCallback

func SLogWithCallback[A any](
	logLevel slog.Level,
	cb func(context.Context) *slog.Logger,
	message string) Kleisli[Result[A], A]

SLogWithCallback creates a Kleisli arrow that logs a Result value (success or error) with a custom logger and log level.

This function logs both successful values and errors, making it useful for debugging and monitoring Result values as they flow through a computation. Unlike TapSLog which only logs successful values, SLogWithCallback logs the Result regardless of whether it contains a value or an error.

The logged output includes:

  • For success: The message with the value as a structured "value" attribute
  • For error: The message with the error as a structured "error" attribute

The Result is passed through unchanged after logging.

Type Parameters:

  • A: The success type of the Result

Parameters:

  • logLevel: The slog.Level to use for logging (e.g., slog.LevelInfo, slog.LevelDebug)
  • cb: Callback function to retrieve the *slog.Logger from the context
  • message: A descriptive message to include in the log entry

Returns:

  • A Kleisli arrow that logs the Result (value or error) and returns it unchanged

Example with custom log level:

debugLog := SLogWithCallback[User](
    slog.LevelDebug,
    logging.GetLoggerFromContext,
    "User result",
)

pipeline := F.Pipe2(
    fetchUser(123),
    Chain(debugLog),
    Map(func(u User) string { return u.Name }),
)

Example with custom logger:

type loggerKey int
const myLoggerKey loggerKey = 0

getMyLogger := func(ctx context.Context) *slog.Logger {
    if logger := ctx.Value(myLoggerKey); logger != nil {
        return logger.(*slog.Logger)
    }
    return slog.Default()
}

customLog := SLogWithCallback[Data](
    slog.LevelWarn,
    getMyLogger,
    "Data processing result",
)

Use Cases:

  • Debugging: Log both successful and failed Results in a pipeline
  • Error tracking: Monitor error occurrences with custom log levels
  • Custom logging: Use application-specific loggers and log levels
  • Conditional logging: Enable/disable logging based on logger configuration

func SequenceReader

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

SequenceReader transforms a ReaderIOResult containing a Reader into a function that takes the Reader's environment first, then returns a ReaderIOResult.

This function "flips" or "sequences" the nested structure, changing the order in which parameters are applied. It's particularly useful for point-free style programming where you want to partially apply the inner Reader's environment before dealing with the outer context.

Type transformation:

From: ReaderIOResult[Reader[R, A]]
      = func(context.Context) func() Either[error, func(R) A]

To:   func(context.Context) func(R) IOResult[A]
      = func(context.Context) func(R) func() Either[error, A]

This allows you to:

  1. Provide the context.Context first
  2. Then provide the Reader's environment R
  3. Finally execute the IO effect to get Either[error, A]

Point-free style benefits:

  • Enables partial application of the Reader environment
  • Facilitates composition of Reader-based computations
  • Allows building reusable computation pipelines
  • Supports dependency injection patterns where R represents dependencies

Example:

type Config struct {
    Timeout int
}

// A computation that produces a Reader based on context
func getMultiplier(ctx context.Context) func() Either[error, func(Config) int] {
    return func() Either[error, func(Config) int] {
        return Right[error](func(cfg Config) int {
            return cfg.Timeout * 2
        })
    }
}

// Sequence it to apply Config first
sequenced := SequenceReader[Config, int](getMultiplier)

// Now we can partially apply the Config
cfg := Config{Timeout: 30}
ctx := t.Context()
result := sequenced(ctx)(cfg)() // Returns Right(60)

This is especially useful in point-free style when building computation pipelines:

var pipeline = F.Flow3(
    loadConfig,           // ReaderIOResult[Reader[Database, Config]]
    SequenceReader,       // func(context.Context) func(Database) IOResult[Config]
    applyToDatabase(db),  // IOResult[Config]
)

func SequenceReaderIO

func SequenceReaderIO[R, A any](ma ReaderIOResult[RIO.ReaderIO[R, A]]) Kleisli[R, A]

SequenceReaderIO transforms a ReaderIOResult containing a ReaderIO into a function that takes the ReaderIO's environment first, then returns a ReaderIOResult.

This is similar to SequenceReader but works with ReaderIO, which represents a computation that depends on an environment R and performs IO effects.

Type transformation:

From: ReaderIOResult[ReaderIO[R, A]]
      = func(context.Context) func() Either[error, func(R) func() A]

To:   func(context.Context) func(R) IOResult[A]
      = func(context.Context) func(R) func() Either[error, A]

The key difference from SequenceReader is that the inner computation (ReaderIO) already performs IO effects, so the sequencing combines these effects properly.

Point-free style benefits:

  • Enables composition of ReaderIO-based computations
  • Allows partial application of environment before IO execution
  • Facilitates building effect pipelines with dependency injection
  • Supports layered architecture where R represents service dependencies

Example:

type Database struct {
    ConnectionString string
}

// A computation that produces a ReaderIO based on context
func getQuery(ctx context.Context) func() Either[error, func(Database) func() string] {
    return func() Either[error, func(Database) func() string] {
        return Right[error](func(db Database) func() string {
            return func() string {
                // Perform actual IO here
                return "Query result from " + db.ConnectionString
            }
        })
    }
}

// Sequence it to apply Database first
sequenced := SequenceReaderIO[Database, string](getQuery)

// Partially apply the Database
db := Database{ConnectionString: "localhost:5432"}
ctx := t.Context()
result := sequenced(ctx)(db)() // Executes IO and returns Right("Query result...")

In point-free style, this enables clean composition:

var executeQuery = F.Flow3(
    prepareQuery,         // ReaderIOResult[ReaderIO[Database, QueryResult]]
    SequenceReaderIO,     // func(context.Context) func(Database) IOResult[QueryResult]
    withDatabase(db),     // IOResult[QueryResult]
)

func SequenceReaderResult

func SequenceReaderResult[R, A any](ma ReaderIOResult[RR.ReaderResult[R, A]]) Kleisli[R, A]

SequenceReaderResult transforms a ReaderIOResult containing a ReaderResult into a function that takes the ReaderResult's environment first, then returns a ReaderIOResult.

This is similar to SequenceReader but works with ReaderResult, which represents a computation that depends on an environment R and can fail with an error.

Type transformation:

From: ReaderIOResult[ReaderResult[R, A]]
      = func(context.Context) func() Either[error, func(R) Either[error, A]]

To:   func(context.Context) func(R) IOResult[A]
      = func(context.Context) func(R) func() Either[error, A]

The sequencing properly combines the error handling from both the outer ReaderIOResult and the inner ReaderResult, ensuring that errors from either level are propagated correctly.

Point-free style benefits:

  • Enables composition of error-handling computations with dependency injection
  • Allows partial application of dependencies before error handling
  • Facilitates building validation pipelines with environment dependencies
  • Supports service-oriented architectures with proper error propagation

Example:

type Config struct {
    MaxRetries int
}

// A computation that produces a ReaderResult based on context
func validateRetries(ctx context.Context) func() Either[error, func(Config) Either[error, int]] {
    return func() Either[error, func(Config) Either[error, int]] {
        return Right[error](func(cfg Config) Either[error, int] {
            if cfg.MaxRetries < 0 {
                return Left[int](errors.New("negative retries"))
            }
            return Right[error](cfg.MaxRetries)
        })
    }
}

// Sequence it to apply Config first
sequenced := SequenceReaderResult[Config, int](validateRetries)

// Partially apply the Config
cfg := Config{MaxRetries: 3}
ctx := t.Context()
result := sequenced(ctx)(cfg)() // Returns Right(3)

// With invalid config
badCfg := Config{MaxRetries: -1}
badResult := sequenced(ctx)(badCfg)() // Returns Left(error("negative retries"))

In point-free style, this enables validation pipelines:

var validateAndProcess = F.Flow4(
    loadConfig,              // ReaderIOResult[ReaderResult[Config, Settings]]
    SequenceReaderResult,    // func(context.Context) func(Config) IOResult[Settings]
    applyConfig(cfg),        // IOResult[Settings]
    Chain(processSettings),  // IOResult[Result]
)

func TailRec

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

TailRec implements stack-safe tail recursion for the context-aware ReaderIOResult monad.

This function enables recursive computations that combine four powerful concepts:

  • Context awareness: Automatic cancellation checking via context.Context
  • Environment dependency (Reader aspect): Access to configuration, context, or dependencies
  • Side effects (IO aspect): Logging, file I/O, network calls, etc.
  • Error handling (Either aspect): Computations that can fail with an error

The function uses an iterative loop to execute the recursion, making it safe for deep or unbounded recursion without risking stack overflow. Additionally, it integrates context cancellation checking through WithContext, ensuring that recursive computations can be cancelled gracefully.

How It Works

TailRec takes a Kleisli arrow that returns Trampoline[A, B]:

  • Bounce(A): Continue recursion with the new state A
  • Land(B): Terminate recursion successfully and return the final result B

The function wraps each iteration with WithContext to ensure context cancellation is checked before each recursive step. If the context is cancelled, the recursion terminates early with a context cancellation error.

Type Parameters

  • A: The state type that changes during recursion
  • B: The final result type when recursion terminates successfully

Parameters

  • f: A Kleisli arrow (A => ReaderIOResult[Trampoline[A, B]]) that:
  • Takes the current state A
  • Returns a ReaderIOResult that depends on context.Context
  • Can fail with error (Left in the outer Either)
  • Produces Trampoline[A, B] to control recursion flow (Right in the outer Either)

Returns

A Kleisli arrow (A => ReaderIOResult[B]) that:

  • Takes an initial state A
  • Returns a ReaderIOResult that requires context.Context
  • Can fail with error or context cancellation
  • Produces the final result B after recursion completes

Context Cancellation

Unlike the base readerioresult.TailRec, this version automatically integrates context cancellation checking:

  • Each recursive iteration checks if the context is cancelled
  • If cancelled, recursion terminates immediately with a cancellation error
  • This prevents runaway recursive computations in cancelled contexts
  • Enables responsive cancellation for long-running recursive operations

Use Cases

  1. Cancellable recursive algorithms: - Tree traversals that can be cancelled mid-operation - Graph algorithms with timeout requirements - Recursive parsers that respect cancellation

  2. Long-running recursive computations: - File system traversals with cancellation support - Network operations with timeout handling - Database operations with connection timeout awareness

  3. Interactive recursive operations: - User-initiated operations that can be cancelled - Background tasks with cancellation support - Streaming operations with graceful shutdown

Example: Cancellable Countdown

countdownStep := func(n int) readerioresult.ReaderIOResult[tailrec.Trampoline[int, string]] {
    return func(ctx context.Context) ioeither.IOEither[error, tailrec.Trampoline[int, string]] {
        return func() either.Either[error, tailrec.Trampoline[int, string]] {
            if n <= 0 {
                return either.Right[error](tailrec.Land[int]("Done!"))
            }
            // Simulate some work
            time.Sleep(100 * time.Millisecond)
            return either.Right[error](tailrec.Bounce[string](n - 1))
        }
    }
}

countdown := readerioresult.TailRec(countdownStep)

// With cancellation
ctx, cancel := context.WithTimeout(t.Context(), 500*time.Millisecond)
defer cancel()
result := countdown(10)(ctx)() // Will be cancelled after ~500ms

Example: Cancellable File Processing

type ProcessState struct {
    files     []string
    processed []string
}

processStep := func(state ProcessState) readerioresult.ReaderIOResult[tailrec.Trampoline[ProcessState, []string]] {
    return func(ctx context.Context) ioeither.IOEither[error, tailrec.Trampoline[ProcessState, []string]] {
        return func() either.Either[error, tailrec.Trampoline[ProcessState, []string]] {
            if len(state.files) == 0 {
                return either.Right[error](tailrec.Land[ProcessState](state.processed))
            }

            file := state.files[0]
            // Process file (this could be cancelled via context)
            if err := processFileWithContext(ctx, file); err != nil {
                return either.Left[tailrec.Trampoline[ProcessState, []string]](err)
            }

            return either.Right[error](tailrec.Bounce[[]string](ProcessState{
                files:     state.files[1:],
                processed: append(state.processed, file),
            }))
        }
    }
}

processFiles := readerioresult.TailRec(processStep)
ctx, cancel := context.WithCancel(t.Context())

// Can be cancelled at any point during processing
go func() {
    time.Sleep(2 * time.Second)
    cancel() // Cancel after 2 seconds
}()

result := processFiles(ProcessState{files: manyFiles})(ctx)()

Stack Safety

The iterative implementation ensures that even deeply recursive computations (thousands or millions of iterations) will not cause stack overflow, while still respecting context cancellation:

// Safe for very large inputs with cancellation support
largeCountdown := readerioresult.TailRec(countdownStep)
ctx := t.Context()
result := largeCountdown(1000000)(ctx)() // Safe, no stack overflow

Performance Considerations

  • Each iteration includes context cancellation checking overhead
  • Context checking happens before each recursive step
  • For performance-critical code, consider the cancellation checking cost
  • The WithContext wrapper adds minimal overhead for cancellation safety

See Also

  • readerioresult.TailRec: Base tail recursion without automatic context checking
  • WithContext: Context cancellation wrapper used internally
  • Chain: For sequencing ReaderIOResult computations
  • Ask: For accessing the context
  • Left/Right: For creating error/success values

func TraverseArray

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

TraverseArray transforms an array [[]A] into [[]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[[]B]]. This uses the default applicative behavior (parallel or sequential based on useParallel flag).

Parameters:

  • f: Function that transforms each element into a ReaderIOResult

Returns a function that transforms an array into a ReaderIOResult of an array.

func TraverseArrayPar

func TraverseArrayPar[A, B any](f Kleisli[A, B]) Kleisli[[]A, []B]

TraverseArrayPar transforms an array [[]A] into [[]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[[]B]]. This is the curried version of MonadTraverseArrayPar with parallel execution.

Parameters:

  • f: Function that transforms each element into a ReaderIOResult

Returns a function that transforms an array into a ReaderIOResult of an array.

func TraverseArraySeq

func TraverseArraySeq[A, B any](f Kleisli[A, B]) Kleisli[[]A, []B]

TraverseArraySeq transforms an array [[]A] into [[]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[[]B]]. This is the curried version of MonadTraverseArraySeq with sequential execution.

Parameters:

  • f: Function that transforms each element into a ReaderIOResult

Returns a function that transforms an array into a ReaderIOResult of an array.

func TraverseArrayWithIndex

func TraverseArrayWithIndex[A, B any](f func(int, A) ReaderIOResult[B]) Kleisli[[]A, []B]

TraverseArrayWithIndex transforms an array [[]A] into [[]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[[]B]]. The transformation function receives both the index and the element.

Parameters:

  • f: Function that transforms each element with its index into a ReaderIOResult

Returns a function that transforms an array into a ReaderIOResult of an array.

func TraverseArrayWithIndexPar

func TraverseArrayWithIndexPar[A, B any](f func(int, A) ReaderIOResult[B]) Kleisli[[]A, []B]

TraverseArrayWithIndexPar uses transforms an array [[]A] into [[]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[[]B]]

func TraverseArrayWithIndexSeq

func TraverseArrayWithIndexSeq[A, B any](f func(int, A) ReaderIOResult[B]) Kleisli[[]A, []B]

TraverseArrayWithIndexSeq uses transforms an array [[]A] into [[]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[[]B]]

func TraverseParTuple1

func TraverseParTuple1[F1 ~func(A1) ReaderIOResult[T1], T1, A1 any](f1 F1) Kleisli[tuple.Tuple1[A1], tuple.Tuple1[T1]]

TraverseParTuple1 converts a [tuple.Tuple1[A1]] into a [ReaderIOResult[tuple.Tuple1[T1]]]

func TraverseRecord

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

TraverseRecord transforms a record [map[K]A] into [map[K]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[map[K]B]].

Parameters:

  • f: Function that transforms each value into a ReaderIOResult

Returns a function that transforms a map into a ReaderIOResult of a map.

func TraverseRecordPar

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

TraverseRecordPar uses transforms a record [map[K]A] into [map[K]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[map[K]B]]

func TraverseRecordSeq

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

TraverseRecordSeq uses transforms a record [map[K]A] into [map[K]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[map[K]B]]

func TraverseRecordWithIndex

func TraverseRecordWithIndex[K comparable, A, B any](f func(K, A) ReaderIOResult[B]) Kleisli[map[K]A, map[K]B]

TraverseRecordWithIndex transforms a record [map[K]A] into [map[K]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[map[K]B]]. The transformation function receives both the key and the value.

Parameters:

  • f: Function that transforms each key-value pair into a ReaderIOResult

Returns a function that transforms a map into a ReaderIOResult of a map.

func TraverseRecordWithIndexPar

func TraverseRecordWithIndexPar[K comparable, A, B any](f func(K, A) ReaderIOResult[B]) Kleisli[map[K]A, map[K]B]

TraverseRecordWithIndexPar uses transforms a record [map[K]A] into [map[K]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[map[K]B]]

func TraverseRecordWithIndexSeq

func TraverseRecordWithIndexSeq[K comparable, A, B any](f func(K, A) ReaderIOResult[B]) Kleisli[map[K]A, map[K]B]

TraverseRecordWithIndexSeq uses transforms a record [map[K]A] into [map[K]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[map[K]B]]

func TraverseSeqTuple1

func TraverseSeqTuple1[F1 ~func(A1) ReaderIOResult[T1], T1, A1 any](f1 F1) Kleisli[tuple.Tuple1[A1], tuple.Tuple1[T1]]

TraverseSeqTuple1 converts a [tuple.Tuple1[A1]] into a [ReaderIOResult[tuple.Tuple1[T1]]]

func TraverseTuple1

func TraverseTuple1[F1 ~func(A1) ReaderIOResult[T1], T1, A1 any](f1 F1) Kleisli[tuple.Tuple1[A1], tuple.Tuple1[T1]]

TraverseTuple1 converts a [tuple.Tuple1[A1]] into a [ReaderIOResult[tuple.Tuple1[T1]]]

func WithCloser

func WithCloser[B any, A io.Closer](onCreate ReaderIOResult[A]) Kleisli[Kleisli[A, B], B]

WithCloser creates a resource management function specifically for io.Closer resources. This is a specialized version of WithResource that automatically handles closing of resources that implement the io.Closer interface.

The function ensures that:

  • The resource is created using the onCreate function
  • The resource is automatically closed when the operation completes (success or failure)
  • Any errors during closing are properly handled
  • The resource is closed even if the main operation fails or the context is canceled

Type Parameters:

  • B: The type of value returned by the resource-using function
  • A: The type of resource that implements io.Closer

Parameters:

  • onCreate: ReaderIOResult that creates the io.Closer resource

Returns:

  • A function that takes a resource-using function and returns a ReaderIOResult[B]

Example with file operations:

openFile := func(filename string) ReaderIOResult[*os.File] {
    return TryCatch(func(ctx context.Context) func() (*os.File, error) {
        return func() (*os.File, error) {
            return os.Open(filename)
        }
    })
}

fileReader := WithCloser(openFile("data.txt"))
result := fileReader(func(f *os.File) ReaderIOResult[string] {
    return TryCatch(func(ctx context.Context) func() (string, error) {
        return func() (string, error) {
            data, err := io.ReadAll(f)
            return string(data), err
        }
    })
})

Example with HTTP response:

httpGet := func(url string) ReaderIOResult[*http.Response] {
    return TryCatch(func(ctx context.Context) func() (*http.Response, error) {
        return func() (*http.Response, error) {
            return http.Get(url)
        }
    })
}

responseReader := WithCloser(httpGet("https://api.example.com/data"))
result := responseReader(func(resp *http.Response) ReaderIOResult[[]byte] {
    return TryCatch(func(ctx context.Context) func() ([]byte, error) {
        return func() ([]byte, error) {
            return io.ReadAll(resp.Body)
        }
    })
})

Example with database connection:

openDB := func(dsn string) ReaderIOResult[*sql.DB] {
    return TryCatch(func(ctx context.Context) func() (*sql.DB, error) {
        return func() (*sql.DB, error) {
            return sql.Open("postgres", dsn)
        }
    })
}

dbQuery := WithCloser(openDB("postgres://..."))
result := dbQuery(func(db *sql.DB) ReaderIOResult[[]User] {
    return TryCatch(func(ctx context.Context) func() ([]User, error) {
        return func() ([]User, error) {
            rows, err := db.QueryContext(ctx, "SELECT * FROM users")
            if err != nil {
                return nil, err
            }
            defer rows.Close()
            return scanUsers(rows)
        }
    })
})

func WithContextK

func WithContextK[A, B any](f Kleisli[A, B]) Kleisli[A, B]

WithContextK wraps a Kleisli arrow with context cancellation checking. This ensures that the computation checks for context cancellation before executing, providing a convenient way to add cancellation awareness to Kleisli arrows.

This is particularly useful when composing multiple Kleisli arrows where each step should respect context cancellation.

Type Parameters:

  • A: The input type of the Kleisli arrow
  • B: The output type of the Kleisli arrow

Parameters:

  • f: The Kleisli arrow to wrap with context checking

Returns:

  • A Kleisli arrow that checks for cancellation before executing

Example:

fetchUser := func(id int) ReaderIOResult[User] {
    return func(ctx context.Context) IOResult[User] {
        return func() Result[User] {
            // Long-running operation
            return result.Of(User{ID: id})
        }
    }
}

// Wrap with context checking
safeFetch := WithContextK(fetchUser)

// If context is cancelled, returns immediately without executing fetchUser
ctx, cancel := context.WithCancel(t.Context())
cancel() // Cancel immediately
result := safeFetch(123)(ctx)() // Returns context.Canceled error

func WithResource

func WithResource[A, R, ANY any](onCreate ReaderIOResult[R], onRelease Kleisli[R, ANY]) Kleisli[Kleisli[R, A], A]

WithResource constructs a function that creates a resource, then operates on it and then releases the resource. This implements the RAII (Resource Acquisition Is Initialization) pattern, ensuring that resources are properly released even if the operation fails or the context is canceled.

The resource is created, used, and released in a safe manner:

  • onCreate: Creates the resource
  • The provided function uses the resource
  • onRelease: Releases the resource (always called, even on error)

Parameters:

  • onCreate: ReaderIOResult that creates the resource
  • onRelease: Function to release the resource

Returns a function that takes a resource-using function and returns a ReaderIOResult.

Example:

file := WithResource(
    openFile("data.txt"),
    func(f *os.File) ReaderIOResult[any] {
        return TryCatch(func(ctx context.Context) func() (any, error) {
            return func() (any, error) { return nil, f.Close() }
        })
    },
)
result := file(func(f *os.File) ReaderIOResult[string] {
    return TryCatch(func(ctx context.Context) func() (string, error) {
        return func() (string, error) {
            data, err := io.ReadAll(f)
            return string(data), err
        }
    })
})
Example
package main

import (
	"context"
	"io"
	"os"

	B "github.com/IBM/fp-go/v2/bytes"
	F "github.com/IBM/fp-go/v2/function"
	I "github.com/IBM/fp-go/v2/io"
	IOE "github.com/IBM/fp-go/v2/ioeither"
)

var (
	openFile = F.Flow3(
		IOE.Eitherize1(os.Open),
		FromIOEither[*os.File],
		ChainFirstIOK(F.Flow2(
			(*os.File).Name,
			I.Logf[string]("Opened file [%s]"),
		)),
	)
)

func closeFile(f *os.File) ReaderIOResult[string] {
	return F.Pipe1(
		TryCatch(func(_ context.Context) func() (string, error) {
			return func() (string, error) {
				return f.Name(), f.Close()
			}
		}),
		ChainFirstIOK(I.Logf[string]("Closed file [%s]")),
	)
}

func main() {

	stringReader := WithResource[string](openFile("data/file.txt"), closeFile)

	rdr := stringReader(func(f *os.File) ReaderIOResult[string] {
		return F.Pipe2(
			TryCatch(func(_ context.Context) func() ([]byte, error) {
				return func() ([]byte, error) {
					return io.ReadAll(f)
				}
			}),
			ChainFirstIOK(F.Flow2(
				B.Size,
				I.Logf[int]("Read content of length [%d]"),
			)),
			Map(B.ToString),
		)
	})

	contentIOE := F.Pipe2(
		context.Background(),
		rdr,
		IOE.ChainFirstIOK[error](I.Printf[string]("Content: %s")),
	)

	contentIOE()

}
Output:

Content: Carsten

type Lazy

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

Lazy represents a deferred computation that produces a value of type A when executed. The computation is not executed until explicitly invoked.

type Lens

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

type LoggingID

type LoggingID uint64

LoggingID is a unique identifier assigned to each logged operation for correlation

type Monoid

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

func AltMonoid

func AltMonoid[A any](zero Lazy[ReaderIOResult[A]]) Monoid[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[A any](m monoid.Monoid[A]) Monoid[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[A any](m monoid.Monoid[A]) Monoid[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[A any](m monoid.Monoid[A]) Monoid[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[A any](m monoid.Monoid[A]) Monoid[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[A, B any] = Kleisli[ReaderIOResult[A], B]

Operator represents a transformation from one ReaderIOResult to another. This is useful for point-free style composition and building reusable transformations.

Operator[A, B] is equivalent to Kleisli[ReaderIOResult[A], B]

Example usage:

// Define a reusable transformation
var toUpper Operator[string, string] = Map(strings.ToUpper)

// Apply the transformation
result := toUpper(computation)

func Alt

func Alt[A any](second Lazy[ReaderIOResult[A]]) Operator[A, A]

Alt provides an alternative ReaderIOResult if the first one fails. This is the curried version of MonadAlt.

Parameters:

  • second: Lazy alternative ReaderIOResult to use if first fails

Returns a function that provides fallback behavior.

func Ap

func Ap[B, A any](fa ReaderIOResult[A]) Operator[func(A) B, B]

Ap applies a function wrapped in a ReaderIOResult to a value wrapped in a ReaderIOResult. This is the curried version of MonadAp, using the default execution mode.

Parameters:

  • fa: ReaderIOResult containing a value

Returns a function that applies a ReaderIOResult function to the value.

func ApEitherS

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

func ApEitherSL

func ApEitherSL[S, T any](
	lens Lens[S, T],
	fa Result[T],
) Operator[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

func ApIOEitherS

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

ApIOEitherS is an applicative variant that works with IOEither values. Unlike BindIOEitherK, this uses applicative composition (ApS) instead of monadic composition (Bind), allowing independent computations to be combined.

Parameters:

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

func ApIOEitherSL

func ApIOEitherSL[S, T any](
	lens Lens[S, T],
	fa IOResult[T],
) Operator[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

func ApIOResultS

func ApIOResultS[S1, S2, T any](
	setter func(T) func(S1) S2,
	fa IOResult[T],
) Operator[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[S, T any](
	lens Lens[S, T],
	fa IOResult[T],
) Operator[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[S1, S2, T any](
	setter func(T) func(S1) S2,
	fa IO[T],
) Operator[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

func ApIOSL

func ApIOSL[S, T any](
	lens Lens[S, T],
	fa IO[T],
) Operator[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

func ApPar

func ApPar[B, A any](fa ReaderIOResult[A]) Operator[func(A) B, B]

ApPar applies a function wrapped in a ReaderIOResult to a value in parallel. This is the curried version of MonadApPar.

Parameters:

  • fa: ReaderIOResult containing a value

Returns a function that applies a ReaderIOResult function to the value in parallel.

func ApReaderIOS

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

ApReaderIOS is an applicative variant that works with ReaderIO values. It lifts a ReaderIO value (with context.Context) 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[S, T any](
	lens Lens[S, T],
	fa ReaderIO[T],
) Operator[S, S]

ApReaderIOSL is a lens-based variant of ApReaderIOS. It combines a lens with a ReaderIO value (with context.Context) using applicative composition.

Parameters:

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

func ApReaderS

func ApReaderS[S1, S2, T any](
	setter func(T) func(S1) S2,
	fa Reader[context.Context, T],
) Operator[S1, S2]

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

Parameters:

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

func ApReaderSL

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

ApReaderSL is a lens-based variant of ApReaderS. It combines a lens with a Reader value (with context.Context) using applicative composition.

Parameters:

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

func ApResultS

func ApResultS[S1, S2, T any](
	setter func(T) func(S1) S2,
	fa Result[T],
) Operator[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[S, T any](
	lens Lens[S, T],
	fa Result[T],
) Operator[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[S1, S2, T any](
	setter func(T) func(S1) S2,
	fa ReaderIOResult[T],
) Operator[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
    Config Config
}

// These operations are independent and can be combined with ApS
getUser := func(ctx context.Context) ioeither.IOEither[error, User] {
    return ioeither.TryCatch(func() (User, error) {
        return fetchUser(ctx)
    })
}
getConfig := func(ctx context.Context) ioeither.IOEither[error, Config] {
    return ioeither.TryCatch(func() (Config, error) {
        return fetchConfig(ctx)
    })
}

result := F.Pipe2(
    readerioeither.Do(State{}),
    readerioeither.ApS(
        func(user User) func(State) State {
            return func(s State) State { s.User = user; return s }
        },
        getUser,
    ),
    readerioeither.ApS(
        func(cfg Config) func(State) State {
            return func(s State) State { s.Config = cfg; return s }
        },
        getConfig,
    ),
)

func ApSL

func ApSL[S, T any](
	lens Lens[S, T],
	fa ReaderIOResult[T],
) Operator[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
    Config Config
}

userLens := lens.MakeLens(
    func(s State) User { return s.User },
    func(s State, u User) State { s.User = u; return s },
)

getUser := func(ctx context.Context) ioeither.IOEither[error, User] {
    return ioeither.TryCatch(func() (User, error) {
        return fetchUser(ctx)
    })
}
result := F.Pipe2(
    readerioeither.Of(State{}),
    readerioeither.ApSL(userLens, getUser),
)

func ApSeq

func ApSeq[B, A any](fa ReaderIOResult[A]) Operator[func(A) B, B]

ApSeq applies a function wrapped in a ReaderIOResult to a value sequentially. This is the curried version of MonadApSeq.

Parameters:

  • fa: ReaderIOResult containing a value

Returns a function that applies a ReaderIOResult function to the value sequentially.

func Bind

func Bind[S1, S2, T any](
	setter func(T) func(S1) S2,
	f Kleisli[S1, T],
) Operator[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 context.Context from the environment.

The setter function takes the result of the computation and returns a function that updates the context from S1 to S2.

Example:

type State struct {
    User   User
    Config Config
}

result := F.Pipe2(
    readerioeither.Do(State{}),
    readerioeither.Bind(
        func(user User) func(State) State {
            return func(s State) State { s.User = user; return s }
        },
        func(s State) readerioeither.ReaderIOResult[User] {
            return func(ctx context.Context) ioeither.IOEither[error, User] {
                return ioeither.TryCatch(func() (User, error) {
                    return fetchUser(ctx)
                })
            }
        },
    ),
    readerioeither.Bind(
        func(cfg Config) func(State) State {
            return func(s State) State { s.Config = cfg; return s }
        },
        func(s State) readerioeither.ReaderIOResult[Config] {
            // This can access s.User from the previous step
            return func(ctx context.Context) ioeither.IOEither[error, Config] {
                return ioeither.TryCatch(func() (Config, error) {
                    return fetchConfigForUser(ctx, s.User.ID)
                })
            }
        },
    ),
)

func BindEitherK

func BindEitherK[S1, S2, T any](
	setter func(T) func(S1) S2,
	f result.Kleisli[S1, T],
) Operator[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])

func BindIOEitherK

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

BindIOEitherK is a variant of Bind that works with IOEither computations. It lifts an IOEither Kleisli arrow into the ReaderIOResult context (with context.Context as environment).

Parameters:

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

func BindIOEitherKL

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

func BindIOK

func BindIOK[S1, S2, T any](
	setter func(T) func(S1) S2,
	f io.Kleisli[S1, T],
) Operator[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])

func BindIOKL

func BindIOKL[S, T any](
	lens Lens[S, T],
	f io.Kleisli[T, T],
) Operator[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])

func BindIOResultK

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

BindIOResultK is a variant of Bind that works with IOResult computations. This is an alias for BindIOEitherK for consistency with the Result naming convention.

Parameters:

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

func BindIOResultKL

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

BindIOResultKL is a lens-based variant of BindIOResultK. This is an alias for BindIOEitherKL for consistency with the Result naming convention.

Parameters:

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

func BindL

func BindL[S, T any](
	lens Lens[S, T],
	f Kleisli[T, T],
) Operator[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
    Config Config
}

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(State{}),
    readerioeither.BindL(userLens, func(user User) readerioeither.ReaderIOResult[User] {
        return func(ctx context.Context) ioeither.IOEither[error, User] {
            return ioeither.TryCatch(func() (User, error) {
                return fetchUser(ctx)
            })
        }
    }),
)

func BindReaderIOK

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

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

Parameters:

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

func BindReaderIOKL

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

BindReaderIOKL is a lens-based variant of BindReaderIOK. It combines a lens with a ReaderIO Kleisli arrow (with context.Context), 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[context.Context, T])

func BindReaderK

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

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

Parameters:

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

func BindReaderKL

func BindReaderKL[S, T any](
	lens Lens[S, T],
	f reader.Kleisli[context.Context, T, T],
) Operator[S, S]

BindReaderKL is a lens-based variant of BindReaderK. It combines a lens with a Reader Kleisli arrow (with context.Context), 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[context.Context, T])

func BindResultK

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

BindResultK is a variant of Bind that works with Result computations. This is an alias for BindEitherK for consistency with the Result naming convention.

Parameters:

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

func BindTo

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

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

func BindToP

func BindToP[S1, T any](
	setter Prism[S1, T],
) Operator[T, S1]

func Chain

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

Chain sequences two ReaderIOResult computations, where the second depends on the result of the first. This is the curried version of MonadChain, useful for composition.

Parameters:

  • f: Function that produces the second ReaderIOResult based on the first's result

Returns a function that sequences ReaderIOResult computations.

func ChainConsumer

func ChainConsumer[A any](c Consumer[A]) Operator[A, struct{}]

ChainConsumer chains a consumer function into a ReaderIOResult computation, discarding the original value. This is useful for performing side effects (like logging or metrics) that consume a value but don't produce a meaningful result. The computation continues with an empty struct.

Type Parameters:

  • A: The type of value to consume

Parameters:

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

Returns:

  • An Operator that chains the consumer and returns struct{}

Example:

logUser := func(u User) {
    log.Printf("Processing user: %s", u.Name)
}

pipeline := F.Pipe2(
    fetchUser(123),
    ChainConsumer(logUser),
)

func ChainEitherK

func ChainEitherK[A, B any](f either.Kleisli[error, A, B]) Operator[A, B]

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

Parameters:

  • f: Function that produces an Either

Returns a function that chains the Either-returning function.

func ChainFirst

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

ChainFirst sequences two ReaderIOResult computations but returns the result of the first. This is the curried version of MonadChainFirst.

Parameters:

  • f: Function that produces the second ReaderIOResult

Returns a function that sequences ReaderIOResult computations.

func ChainFirstConsumer

func ChainFirstConsumer[A any](c Consumer[A]) Operator[A, A]

ChainFirstConsumer chains a consumer function into a ReaderIOResult computation, preserving the original value. This is useful for performing side effects (like logging or metrics) while passing the value through unchanged.

The consumer is executed for its side effects, but the original value is returned.

Type Parameters:

  • A: The type of value to consume and return

Parameters:

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

Returns:

  • An Operator that chains the consumer and returns the original value

Example:

logUser := func(u User) {
    log.Printf("User: %s", u.Name)
}

pipeline := F.Pipe3(
    fetchUser(123),
    ChainFirstConsumer(logUser),  // Logs but passes user through
    Map(func(u User) string { return u.Email }),
)

func ChainFirstEitherK

func ChainFirstEitherK[A, B any](f either.Kleisli[error, A, B]) Operator[A, A]

ChainFirstEitherK chains a function that returns an Either but keeps the original value. This is the curried version of MonadChainFirstEitherK.

Parameters:

  • f: Function that produces an Either

Returns a function that chains the Either-returning function.

func ChainFirstIOK

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

ChainFirstIOK chains a function that returns an IO but keeps the original value. This is the curried version of MonadChainFirstIOK.

Parameters:

  • f: Function that produces an IO

Returns a function that chains the IO-returning function.

func ChainFirstLeft

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

ChainFirstLeft is the curried version of MonadChainFirstLeft. It returns a function that chains a computation on the left (error) side while always preserving the original error.

This is particularly useful for adding error handling side effects (like logging, metrics, or notifications) in a functional pipeline. The original error is always returned regardless of what f returns (Left or Right), ensuring the error path is preserved.

func ChainFirstLeftIOK added in v2.1.1

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

func ChainFirstReaderIOK

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

func ChainFirstReaderK

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

func ChainFirstReaderResultK

func ChainFirstReaderResultK[A, B any](f readerresult.Kleisli[A, B]) Operator[A, A]

func ChainIOEitherK

func ChainIOEitherK[A, B any](f ioresult.Kleisli[A, B]) Operator[A, B]

ChainIOEitherK chains a function that returns an IOResult into a ReaderIOResult computation. This is useful for integrating IOResult-returning functions into ReaderIOResult workflows.

Parameters:

  • f: Function that produces an IOResult

Returns a function that chains the IOResult-returning function.

func ChainIOK

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

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

Parameters:

  • f: Function that produces an IO

Returns a function that chains the IO-returning function.

func ChainLeft

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

ChainLeft is the curried version of MonadChainLeft. It returns a function that chains a computation on the left (error) side of a ReaderIOResult.

func ChainReaderIOK

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

func ChainReaderK

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

func ChainReaderResultK

func ChainReaderResultK[A, B any](f readerresult.Kleisli[A, B]) Operator[A, B]

func ChainResultK

func ChainResultK[A, B any](f either.Kleisli[error, A, B]) Operator[A, B]

func Contramap added in v2.1.6

func Contramap[A any](f func(context.Context) (context.Context, context.CancelFunc)) Operator[A, A]

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

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

Contramap is an alias for Local and is useful for adapting a ReaderIOResult to work with a modified context by providing a function that transforms the context.

Type Parameters:

  • A: The success type (unchanged)

Parameters:

  • f: Function to transform the context, returning a new context and CancelFunc

Returns:

  • An Operator that takes a ReaderIOResult[A] and returns a ReaderIOResult[A]

func Delay

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

Delay creates an operation that delays execution by the specified duration. The computation waits for either the delay to expire or the context to be canceled.

Parameters:

  • delay: The duration to wait before executing the computation

Returns a function that delays a ReaderIOResult computation.

func FilterOrElse added in v2.1.0

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

FilterOrElse filters a ReaderIOResult value based on a predicate. This is a convenience wrapper around readerioresult.FilterOrElse that fixes the context type to context.Context.

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.

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:

// Validate that a number is positive
isPositive := N.MoreThan(0)
onNegative := func(n int) error { return fmt.Errorf("%d is not positive", n) }

filter := readerioresult.FilterOrElse(isPositive, onNegative)
result := filter(readerioresult.Right(42))(t.Context())()

func Flap

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

Flap applies a value to a function wrapped in a ReaderIOResult. This is the curried version of MonadFlap.

Parameters:

  • a: The value to apply to the function

Returns a function that applies the value to a ReaderIOResult function.

func Fold

func Fold[A, B any](onLeft Kleisli[error, B], onRight Kleisli[A, B]) Operator[A, B]

Fold handles both success and error cases of a ReaderIOResult by providing handlers for each. Both handlers return ReaderIOResult, allowing for further composition.

Parameters:

  • onLeft: Handler for error case
  • onRight: Handler for success case

Returns a function that folds a ReaderIOResult into a new ReaderIOResult.

func Let

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

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

func LetL

func LetL[S, T any](
	lens Lens[S, T],
	f Endomorphism[T],
) Operator[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
    Config Config
}

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(State{User: User{Name: "Alice"}}),
    readerioeither.LetL(userLens, func(user User) User {
        user.Name = "Bob"
        return user
    }),
)

func LetTo

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

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

func LetToL

func LetToL[S, T any](
	lens Lens[S, T],
	b T,
) Operator[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
    Config Config
}

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(State{}),
    readerioeither.LetToL(userLens, newUser),
)

func Local

func Local[A any](f func(context.Context) (context.Context, context.CancelFunc)) Operator[A, A]

Local transforms the context.Context environment before passing it to a ReaderIOResult computation.

This is the Reader's local operation, which allows you to modify the environment for a specific computation without affecting the outer context. The transformation function receives the current context and returns a new context along with a cancel function. The cancel function is automatically called when the computation completes (via defer), ensuring proper cleanup of resources.

The function checks for context cancellation before applying the transformation, returning an error immediately if the context is already cancelled.

This is useful for:

  • Adding timeouts or deadlines to specific operations
  • Adding context values for nested computations
  • Creating isolated context scopes
  • Implementing context-based dependency injection

Type Parameters:

  • A: The value type of the ReaderIOResult

Parameters:

  • f: A function that transforms the context and returns a cancel function

Returns:

  • An Operator that runs the computation with the transformed context

Example:

import F "github.com/IBM/fp-go/v2/function"

// Add a custom value to the context
type key int
const userKey key = 0

addUser := readerioresult.Local[string](func(ctx context.Context) (context.Context, context.CancelFunc) {
    newCtx := context.WithValue(ctx, userKey, "Alice")
    return newCtx, func() {} // No-op cancel
})

getUser := readerioresult.FromReader(func(ctx context.Context) string {
    if user := ctx.Value(userKey); user != nil {
        return user.(string)
    }
    return "unknown"
})

result := F.Pipe1(
    getUser,
    addUser,
)
value, err := result(t.Context())()  // Returns ("Alice", nil)

Timeout Example:

// Add a 5-second timeout to a specific operation
withTimeout := readerioresult.Local[Data](func(ctx context.Context) (context.Context, context.CancelFunc) {
    return context.WithTimeout(ctx, 5*time.Second)
})

result := F.Pipe1(
    fetchData,
    withTimeout,
)

func LogEntryExit

func LogEntryExit[A any](name string) Operator[A, A]

LogEntryExit creates an operator that logs the entry and exit of a ReaderIOResult computation with timing and correlation IDs.

This function wraps a ReaderIOResult computation with automatic logging that tracks:

  • Entry: Logs when the computation starts with "[entering <id>] <name>"
  • Exit: Logs when the computation completes successfully with "[exiting <id>] <name> [duration]"
  • Error: Logs when the computation fails with "[throwing <id>] <name> [duration]: <error>"

Each logged operation is assigned a unique LoggingID (a monotonically increasing counter) that appears in all log messages for that operation. This ID enables correlation of entry and exit logs, even when multiple operations are running concurrently or are interleaved.

The logging information (start time and ID) is stored in the context and can be retrieved using getLoggingContext or getLoggingID. This allows nested operations to access the parent operation's logging information.

Type Parameters:

  • A: The success type of the ReaderIOResult

Parameters:

  • name: A descriptive name for the computation, used in log messages to identify the operation

Returns:

  • An Operator that wraps the ReaderIOResult computation with entry/exit logging

The function uses the bracket pattern to ensure that:

  • Entry is logged before the computation starts
  • A unique LoggingID is assigned and stored in the context
  • Exit/error is logged after the computation completes, regardless of success or failure
  • Timing is accurate, measuring from entry to exit
  • The original result is preserved and returned unchanged

Log Format:

  • Entry: "[entering <id>] <name>"
  • Success: "[exiting <id>] <name> [<duration>s]"
  • Error: "[throwing <id>] <name> [<duration>s]: <error>"

Example with successful computation:

fetchUser := func(id int) ReaderIOResult[User] {
    return Of(User{ID: id, Name: "Alice"})
}

// Wrap with logging
loggedFetch := LogEntryExit[User]("fetchUser")(fetchUser(123))

// Execute
result := loggedFetch(t.Context())()
// Logs:
// [entering 1] fetchUser
// [exiting  1] fetchUser [0.1s]

Example with error:

failingOp := func() ReaderIOResult[string] {
    return Left[string](errors.New("connection timeout"))
}

logged := LogEntryExit[string]("failingOp")(failingOp())
result := logged(t.Context())()
// Logs:
// [entering 2] failingOp
// [throwing 2] failingOp [0.0s]: connection timeout

Example with nested operations:

fetchOrders := func(userID int) ReaderIOResult[[]Order] {
    return Of([]Order{{ID: 1}})
}

pipeline := F.Pipe3(
    fetchUser(123),
    LogEntryExit[User]("fetchUser"),
    Chain(func(user User) ReaderIOResult[[]Order] {
        return fetchOrders(user.ID)
    }),
    LogEntryExit[[]Order]("fetchOrders"),
)

result := pipeline(t.Context())()
// Logs:
// [entering 3] fetchUser
// [exiting  3] fetchUser [0.1s]
// [entering 4] fetchOrders
// [exiting  4] fetchOrders [0.2s]

Example with concurrent operations:

// Multiple operations can run concurrently, each with unique IDs
op1 := LogEntryExit[Data]("operation1")(fetchData(1))
op2 := LogEntryExit[Data]("operation2")(fetchData(2))

go op1(t.Context())()
go op2(t.Context())()
// Logs (order may vary):
// [entering 5] operation1
// [entering 6] operation2
// [exiting  5] operation1 [0.1s]
// [exiting  6] operation2 [0.2s]
// The IDs allow correlation even when logs are interleaved

Use Cases:

  • Debugging: Track execution flow through complex ReaderIOResult chains with correlation IDs
  • Performance monitoring: Identify slow operations with timing information
  • Production logging: Monitor critical operations with unique identifiers
  • Concurrent operations: Correlate logs from multiple concurrent operations
  • Nested operations: Track parent-child relationships in operation hierarchies
  • Troubleshooting: Quickly identify where errors occur and correlate with entry logs

func LogEntryExitF

func LogEntryExitF[A, ANY any](
	onEntry ReaderIO[context.Context],
	onExit readerio.Kleisli[Result[A], ANY],
) Operator[A, A]

LogEntryExitF creates a customizable operator that wraps a ReaderIOResult computation with entry/exit callbacks.

This is a more flexible version of LogEntryExit that allows you to provide custom callbacks for entry and exit events. The onEntry callback receives the current context and can return a modified context (e.g., with additional logging information). The onExit callback receives the computation result and can perform custom logging, metrics collection, or cleanup.

The function uses the bracket pattern to ensure that:

  • The onEntry callback is executed before the computation starts
  • The computation runs with the context returned by onEntry
  • The onExit callback is executed after the computation completes (success or failure)
  • The original result is preserved and returned unchanged
  • Cleanup happens even if the computation fails

Type Parameters:

  • A: The success type of the ReaderIOResult
  • ANY: The return type of the onExit callback (typically any)

Parameters:

  • onEntry: A ReaderIO that receives the current context and returns a (possibly modified) context. This is executed before the computation starts. Use this for logging entry, adding context values, starting timers, or initialization logic.
  • onExit: A Kleisli function that receives the Result[A] and returns a ReaderIO[ANY]. This is executed after the computation completes, regardless of success or failure. Use this for logging exit, recording metrics, cleanup, or finalization logic.

Returns:

  • An Operator that wraps the ReaderIOResult computation with the custom entry/exit callbacks

Example with custom context modification:

type RequestID string

logOp := LogEntryExitF[User, any](
    func(ctx context.Context) IO[context.Context] {
        return func() context.Context {
            reqID := RequestID(uuid.New().String())
            log.Printf("[%s] Starting operation", reqID)
            return context.WithValue(ctx, "requestID", reqID)
        }
    },
    func(res Result[User]) ReaderIO[any] {
        return func(ctx context.Context) IO[any] {
            return func() any {
                reqID := ctx.Value("requestID").(RequestID)
                return F.Pipe1(
                    res,
                    result.Fold(
                        func(err error) any {
                            log.Printf("[%s] Operation failed: %v", reqID, err)
                            return nil
                        },
                        func(_ User) any {
                            log.Printf("[%s] Operation succeeded", reqID)
                            return nil
                        },
                    ),
                )
            }
        }
    },
)

wrapped := logOp(fetchUser(123))

Example with metrics collection:

import "github.com/prometheus/client_golang/prometheus"

metricsOp := LogEntryExitF[Response, any](
    func(ctx context.Context) IO[context.Context] {
        return func() context.Context {
            requestCount.WithLabelValues("api_call", "started").Inc()
            return context.WithValue(ctx, "startTime", time.Now())
        }
    },
    func(res Result[Response]) ReaderIO[any] {
        return func(ctx context.Context) IO[any] {
            return func() any {
                startTime := ctx.Value("startTime").(time.Time)
                duration := time.Since(startTime).Seconds()

                return F.Pipe1(
                    res,
                    result.Fold(
                        func(err error) any {
                            requestCount.WithLabelValues("api_call", "error").Inc()
                            requestDuration.WithLabelValues("api_call", "error").Observe(duration)
                            return nil
                        },
                        func(_ Response) any {
                            requestCount.WithLabelValues("api_call", "success").Inc()
                            requestDuration.WithLabelValues("api_call", "success").Observe(duration)
                            return nil
                        },
                    ),
                )
            }
        }
    },
)

Use Cases:

  • Custom context modification: Adding request IDs, trace IDs, or other context values
  • Structured logging: Integration with zap, logrus, or other structured loggers
  • Metrics collection: Recording operation durations, success/failure rates
  • Distributed tracing: OpenTelemetry, Jaeger integration
  • Custom monitoring: Application-specific monitoring and alerting

Note: LogEntryExit is implemented using LogEntryExitF with standard logging and context management. Use LogEntryExitF when you need more control over the entry/exit behavior or context modification.

func LogEntryExitWithCallback

func LogEntryExitWithCallback[A any](
	logLevel slog.Level,
	cb func(context.Context) *slog.Logger,
	name string) Operator[A, A]

LogEntryExitWithCallback creates an operator that logs entry and exit of a ReaderIOResult computation using a custom logger callback and log level. This provides more control than LogEntryExit.

This function allows you to:

  • Use a custom log level (Debug, Info, Warn, Error)
  • Retrieve the logger from the context using a custom callback
  • Control whether logging is enabled based on the logger's configuration

Type Parameters:

  • A: The success type of the ReaderIOResult

Parameters:

  • logLevel: The slog.Level to use for all log messages (entry, exit, error)
  • cb: Callback function to retrieve the *slog.Logger from the context
  • name: A descriptive name for the operation

Returns:

  • An Operator that wraps the ReaderIOResult with customizable logging

Example with custom log level:

// Log at debug level
debugOp := LogEntryExitWithCallback[User](
    slog.LevelDebug,
    logging.GetLoggerFromContext,
    "fetchUser",
)
result := debugOp(fetchUser(123))

Example with custom logger callback:

type loggerKey int
const myLoggerKey loggerKey = 0

getMyLogger := func(ctx context.Context) *slog.Logger {
    if logger := ctx.Value(myLoggerKey); logger != nil {
        return logger.(*slog.Logger)
    }
    return slog.Default()
}

customOp := LogEntryExitWithCallback[Data](
    slog.LevelInfo,
    getMyLogger,
    "processData",
)

func MakeSingletonBreaker added in v2.1.1

func MakeSingletonBreaker[T any](
	currentTime IO[time.Time],
	closedState ClosedState,
	checkError option.Kleisli[error, error],
	policy retry.RetryPolicy,
	metrics circuitbreaker.Metrics,
) Operator[T, T]

func Map

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

Map transforms the success value of a ReaderIOResult using the provided function. This is the curried version of MonadMap, useful for composition.

Parameters:

  • f: The transformation function

Returns a function that transforms a ReaderIOResult.

func MapTo

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

MapTo replaces the success value of a ReaderIOResult with a constant value. This is the curried version of MonadMapTo.

Parameters:

  • b: The constant value to use

Returns a function that transforms a ReaderIOResult.

func OrElse

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

OrElse provides an alternative ReaderIOResult computation if the first one fails. The alternative is only executed if the first computation results in a Left (error).

Parameters:

  • onLeft: Function that produces an alternative ReaderIOResult from the error

Returns a function that provides fallback behavior for failed computations.

func OrLeft

func OrLeft[A any](onLeft func(error) ReaderIO[error]) Operator[A, A]

OrLeft transforms the error of a ReaderIOResult using the provided function. The success value is left unchanged.

Parameters:

  • onLeft: Function to transform the error

Returns a function that transforms the error of a ReaderIOResult.

func Promap added in v2.1.6

func Promap[A, B any](f func(context.Context) (context.Context, context.CancelFunc), g func(A) B) Operator[A, B]

Promap is the profunctor map operation that transforms both the input and output of a context-based ReaderIOResult. It applies f to the input context (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:

  • Modify the context before passing it to the ReaderIOResult (via f)
  • Transform the success value after the IO effect completes (via g)

The function f returns both a new context and a CancelFunc that should be called to release resources. The error type is fixed as error and remains unchanged through the transformation.

Type Parameters:

  • A: The original success type produced by the ReaderIOResult
  • B: The new output success type

Parameters:

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

Returns:

  • An Operator that takes a ReaderIOResult[A] and returns a ReaderIOResult[B]

func Tap

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

func TapEitherK

func TapEitherK[A, B any](f either.Kleisli[error, A, B]) Operator[A, A]

func TapIOK

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

func TapLeft

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

func TapLeftIOK added in v2.1.1

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

func TapReaderIOK

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

func TapReaderK

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

func TapReaderResultK

func TapReaderResultK[A, B any](f readerresult.Kleisli[A, B]) Operator[A, A]

func TapSLog

func TapSLog[A any](message string) Operator[A, A]

TapSLog creates an operator that logs only successful values with a message and passes them through unchanged.

This function is useful for debugging and monitoring values as they flow through a ReaderIOResult computation chain. Unlike SLog which logs both successes and errors, TapSLog only logs when the computation is successful. If the computation contains an error, no logging occurs and the error is propagated unchanged.

The logged output includes:

  • The provided message
  • The value being passed through (as a structured "value" attribute)

Type Parameters:

  • A: The type of the value to log and pass through

Parameters:

  • message: A descriptive message to include in the log entry

Returns:

  • An Operator that logs successful values and returns them unchanged

Example with simple value logging:

fetchUser := func(id int) ReaderIOResult[User] {
    return Of(User{ID: id, Name: "Alice"})
}

pipeline := F.Pipe2(
    fetchUser(123),
    TapSLog[User]("Fetched user"),
    Map(func(u User) string { return u.Name }),
)

result := pipeline(t.Context())()
// Logs: "Fetched user" value={ID:123 Name:"Alice"}
// Returns: result.Of("Alice")

Example in a processing pipeline:

processOrder := F.Pipe4(
    fetchOrder(orderId),
    TapSLog[Order]("Order fetched"),
    Chain(validateOrder),
    TapSLog[Order]("Order validated"),
    Chain(processPayment),
    TapSLog[Payment]("Payment processed"),
)

result := processOrder(t.Context())()
// Logs each successful step with the intermediate values
// If any step fails, subsequent TapSLog calls don't log

Example with error handling:

pipeline := F.Pipe3(
    fetchData(id),
    TapSLog[Data]("Data fetched"),
    Chain(func(d Data) ReaderIOResult[Result] {
        if d.IsValid() {
            return Of(processData(d))
        }
        return Left[Result](errors.New("invalid data"))
    }),
    TapSLog[Result]("Data processed"),
)

// If fetchData succeeds: logs "Data fetched" with the data
// If processing succeeds: logs "Data processed" with the result
// If processing fails: "Data processed" is NOT logged (error propagates)

Use Cases:

  • Debugging: Inspect intermediate successful values in a computation pipeline
  • Monitoring: Track successful data flow through complex operations
  • Troubleshooting: Identify where successful computations stop (last logged value before error)
  • Auditing: Log important successful values for compliance or security
  • Development: Understand data transformations during development

Note: This function only logs successful values. Errors are silently propagated without logging. For logging both successes and errors, use SLog instead.

func WithDeadline

func WithDeadline[A any](deadline time.Time) Operator[A, A]

WithDeadline adds an absolute deadline to the context for a ReaderIOResult computation.

This is a convenience wrapper around Local that uses context.WithDeadline. The computation must complete before the specified time, or it will be cancelled. This is useful for coordinating operations that must finish by a specific time, such as request deadlines or scheduled tasks.

The deadline is an absolute time, unlike WithTimeout which uses a relative duration. The cancel function is automatically called when the computation completes, ensuring proper cleanup. If the deadline passes, the computation will receive a context.DeadlineExceeded error.

Type Parameters:

  • A: The value type of the ReaderIOResult

Parameters:

  • deadline: The absolute time by which the computation must complete

Returns:

  • An Operator that runs the computation with a deadline

Example:

import (
    "time"
    F "github.com/IBM/fp-go/v2/function"
)

// Operation must complete by 3 PM
deadline := time.Date(2024, 1, 1, 15, 0, 0, 0, time.UTC)

fetchData := readerioresult.FromReader(func(ctx context.Context) Data {
    // Simulate operation
    select {
    case <-time.After(1 * time.Hour):
        return Data{Value: "done"}
    case <-ctx.Done():
        return Data{}
    }
})

result := F.Pipe1(
    fetchData,
    readerioresult.WithDeadline[Data](deadline),
)
value, err := result(t.Context())()  // Returns (Data{}, context.DeadlineExceeded) if past deadline

Combining with Parent Context:

// If parent context already has a deadline, the earlier one takes precedence
parentCtx, cancel := context.WithDeadline(t.Context(), time.Now().Add(1*time.Hour))
defer cancel()

laterDeadline := time.Now().Add(2 * time.Hour)
result := F.Pipe1(
    fetchData,
    readerioresult.WithDeadline[Data](laterDeadline),
)
value, err := result(parentCtx)()  // Will use parent's 1-hour deadline

func WithLock

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

WithLock executes the provided IO operation in the scope of a lock. This ensures that the operation is executed with mutual exclusion, preventing concurrent access.

The lock is acquired before the operation and released after it completes (or fails). The lock parameter should return a CancelFunc that releases the lock when called.

Parameters:

  • lock: ReaderIOResult that acquires a lock and returns a CancelFunc to release it

Returns a function that wraps a ReaderIOResult with lock protection.

Example:

mutex := &sync.Mutex{}
lock := TryCatch(func(ctx context.Context) func() (context.CancelFunc, error) {
    return func() (context.CancelFunc, error) {
        mutex.Lock()
        return func() { mutex.Unlock() }, nil
    }
})
protectedOp := WithLock(lock)(myOperation)

func WithTimeout

func WithTimeout[A any](timeout time.Duration) Operator[A, A]

WithTimeout adds a timeout to the context for a ReaderIOResult computation.

This is a convenience wrapper around Local that uses context.WithTimeout. The computation must complete within the specified duration, or it will be cancelled. This is useful for ensuring operations don't run indefinitely and for implementing timeout-based error handling.

The timeout is relative to when the ReaderIOResult is executed, not when WithTimeout is called. The cancel function is automatically called when the computation completes, ensuring proper cleanup. If the timeout expires, the computation will receive a context.DeadlineExceeded error.

Type Parameters:

  • A: The value type of the ReaderIOResult

Parameters:

  • timeout: The maximum duration for the computation

Returns:

  • An Operator that runs the computation with a timeout

Example:

import (
    "time"
    F "github.com/IBM/fp-go/v2/function"
)

// Fetch data with a 5-second timeout
fetchData := readerioresult.FromReader(func(ctx context.Context) Data {
    // Simulate slow operation
    select {
    case <-time.After(10 * time.Second):
        return Data{Value: "slow"}
    case <-ctx.Done():
        return Data{}
    }
})

result := F.Pipe1(
    fetchData,
    readerioresult.WithTimeout[Data](5*time.Second),
)
value, err := result(t.Context())()  // Returns (Data{}, context.DeadlineExceeded) after 5s

Successful Example:

quickFetch := readerioresult.Right(Data{Value: "quick"})
result := F.Pipe1(
    quickFetch,
    readerioresult.WithTimeout[Data](5*time.Second),
)
value, err := result(t.Context())()  // Returns (Data{Value: "quick"}, nil)

type Option

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

Option represents an optional value that may or may not be present. It is used in operations that may not produce a value.

type Pair added in v2.1.1

type Pair[A, B any] = pair.Pair[A, B]

type Predicate added in v2.1.0

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

type Prism

type Prism[S, T any] = prism.Prism[S, T]

type Reader

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

Reader represents a computation that depends on a context of type R. This is used for dependency injection and accessing shared context.

Reader[R, A] is equivalent to func(R) A

type ReaderEither

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

type ReaderIO

type ReaderIO[A any] = readerio.ReaderIO[context.Context, A]

ReaderIO represents a context-dependent computation that performs side effects. This is specialized to use context.Context as the context type.

ReaderIO[A] is equivalent to func(context.Context) func() A

type ReaderIOResult

type ReaderIOResult[A any] = RIOR.ReaderIOResult[context.Context, A]

ReaderIOResult is the main type of this package. It represents a computation that:

  • Depends on a context.Context (Reader aspect)
  • Performs side effects (IO aspect)
  • Can fail with an [error] (Either aspect)
  • Produces a value of type A on success

This is a specialization of [readerioeither.ReaderIOResult] with:

The type is defined as:

ReaderIOResult[A] = func(context.Context) func() Either[error, A]

Example usage:

func fetchUser(id string) ReaderIOResult[User] {
    return func(ctx context.Context) func() Either[error, User] {
        return func() Either[error, User] {
            user, err := userService.Get(ctx, id)
            if err != nil {
                return either.Left[User](err)
            }
            return either.Right[error](user)
        }
    }
}

The computation is executed by providing a context and then invoking the result:

ctx := t.Context()
result := fetchUser("123")(ctx)()

func Ask

func Ask() ReaderIOResult[context.Context]

Ask returns a ReaderIOResult that provides access to the context. This is useful for accessing the context.Context within a computation.

Returns a ReaderIOResult that produces the context.

func Bracket

func Bracket[
	A, B, ANY any](

	acquire ReaderIOResult[A],
	use Kleisli[A, B],
	release func(A, Either[B]) ReaderIOResult[ANY],
) ReaderIOResult[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[A any](gen Lazy[ReaderIOResult[A]]) ReaderIOResult[A]

Defer creates a ReaderIOResult by lazily generating a new computation each time it's executed. This is useful for creating computations that should be re-evaluated on each execution.

Parameters:

  • gen: Lazy generator function that produces a ReaderIOResult

Returns a ReaderIOResult that generates a fresh computation on each execution.

func Do

func Do[S any](
	empty S,
) ReaderIOResult[S]

Do creates an empty context of type [S] to be used with the Bind operation. This is the starting point for do-notation style composition.

Example:

type State struct {
    User   User
    Config Config
}
result := readerioeither.Do(State{})

func Flatten

func Flatten[A any](rdr ReaderIOResult[ReaderIOResult[A]]) ReaderIOResult[A]

Flatten converts a nested ReaderIOResult into a flat ReaderIOResult. This is equivalent to MonadChain with the identity function.

Parameters:

  • rdr: The nested ReaderIOResult to flatten

Returns a flattened ReaderIOResult.

func FromEither

func FromEither[A any](e Either[A]) ReaderIOResult[A]

FromEither converts an Either into a ReaderIOResult. The resulting computation ignores the context and immediately returns the Either value.

Parameters:

  • e: The Either value to lift into ReaderIOResult

Returns a ReaderIOResult that produces the given Either value.

func FromIO

func FromIO[A any](t IO[A]) ReaderIOResult[A]

FromIO converts an IO into a ReaderIOResult. The IO computation always succeeds, so it's wrapped in Right.

Parameters:

  • t: The IO to convert

Returns a ReaderIOResult that executes the IO and wraps the result in Right.

func FromIOEither

func FromIOEither[A any](t IOResult[A]) ReaderIOResult[A]

FromIOEither converts an IOResult into a ReaderIOResult. The resulting computation ignores the context.

Parameters:

  • t: The IOResult to convert

Returns a ReaderIOResult that executes the IOResult.

func FromIOResult

func FromIOResult[A any](t IOResult[A]) ReaderIOResult[A]

func FromLazy

func FromLazy[A any](t Lazy[A]) ReaderIOResult[A]

FromLazy converts a Lazy computation into a ReaderIOResult. The Lazy computation always succeeds, so it's wrapped in Right. This is an alias for FromIO since Lazy and IO have the same structure.

Parameters:

  • t: The Lazy computation to convert

Returns a ReaderIOResult that executes the Lazy computation and wraps the result in Right.

func FromReader

func FromReader[A any](t Reader[context.Context, A]) ReaderIOResult[A]

func FromReaderEither

func FromReaderEither[A any](ma ReaderEither[context.Context, error, A]) ReaderIOResult[A]

func FromReaderIO

func FromReaderIO[A any](t ReaderIO[A]) ReaderIOResult[A]

func FromReaderResult

func FromReaderResult[A any](ma ReaderResult[A]) ReaderIOResult[A]

func FromResult

func FromResult[A any](e Result[A]) ReaderIOResult[A]

FromEither converts an Either into a ReaderIOResult. The resulting computation ignores the context and immediately returns the Either value.

Parameters:

  • e: The Either value to lift into ReaderIOResult

Returns a ReaderIOResult that produces the given Either value.

func Left

func Left[A any](l error) ReaderIOResult[A]

Left creates a ReaderIOResult that represents a failed computation with the given error.

Parameters:

  • l: The error value

Returns a ReaderIOResult that always fails with the given error.

func Memoize

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

Memoize computes the value of the provided ReaderIOResult monad lazily but exactly once. The context used to compute the value is the context of the first call, so do not use this method if the value has a functional dependency on the content of the context.

Parameters:

  • rdr: The ReaderIOResult to memoize

Returns a ReaderIOResult that caches its result after the first execution.

func MonadAlt

func MonadAlt[A any](first ReaderIOResult[A], second Lazy[ReaderIOResult[A]]) ReaderIOResult[A]

MonadAlt provides an alternative ReaderIOResult if the first one fails. The alternative is lazily evaluated only if needed.

Parameters:

  • first: The primary ReaderIOResult to try
  • second: Lazy alternative ReaderIOResult to use if first fails

Returns a ReaderIOResult that tries the first, then the second if first fails.

func MonadAp

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

MonadAp implements applicative application for ReaderIOResult. By default, it uses parallel execution (MonadApPar) but can be configured to use sequential execution (MonadApSeq) via the useParallel constant.

Parameters:

  • fab: ReaderIOResult containing a function
  • fa: ReaderIOResult containing a value

Returns a ReaderIOResult with the function applied to the value.

func MonadApPar

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

MonadApPar implements parallel applicative application for ReaderIOResult. It executes both computations in parallel and creates a sub-context that will be canceled if either operation fails. This provides automatic cancellation propagation.

Parameters:

  • fab: ReaderIOResult containing a function
  • fa: ReaderIOResult containing a value

Returns a ReaderIOResult with the function applied to the value.

func MonadApSeq

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

MonadApSeq implements sequential applicative application for ReaderIOResult. It executes the function computation first, then the value computation.

Parameters:

  • fab: ReaderIOResult containing a function
  • fa: ReaderIOResult containing a value

Returns a ReaderIOResult with the function applied to the value.

func MonadChain

func MonadChain[A, B any](ma ReaderIOResult[A], f Kleisli[A, B]) ReaderIOResult[B]

MonadChain sequences two ReaderIOResult computations, where the second depends on the result of the first. If the first computation fails, the second is not executed.

Parameters:

  • ma: The first ReaderIOResult
  • f: Function that produces the second ReaderIOResult based on the first's result

Returns a new ReaderIOResult representing the sequenced computation.

func MonadChainEitherK

func MonadChainEitherK[A, B any](ma ReaderIOResult[A], f either.Kleisli[error, A, B]) ReaderIOResult[B]

MonadChainEitherK chains a function that returns an Either into a ReaderIOResult computation. This is useful for integrating pure Either-returning functions into ReaderIOResult workflows.

Parameters:

  • ma: The ReaderIOResult to chain from
  • f: Function that produces an Either

Returns a new ReaderIOResult with the chained computation.

func MonadChainFirst

func MonadChainFirst[A, B any](ma ReaderIOResult[A], f Kleisli[A, B]) ReaderIOResult[A]

MonadChainFirst sequences two ReaderIOResult computations but returns the result of the first. The second computation is executed for its side effects only.

Parameters:

  • ma: The first ReaderIOResult
  • f: Function that produces the second ReaderIOResult

Returns a ReaderIOResult with the result of the first computation.

func MonadChainFirstEitherK

func MonadChainFirstEitherK[A, B any](ma ReaderIOResult[A], f either.Kleisli[error, A, B]) ReaderIOResult[A]

MonadChainFirstEitherK chains a function that returns an Either but keeps the original value. The Either-returning function is executed for its validation/side effects only.

Parameters:

  • ma: The ReaderIOResult to chain from
  • f: Function that produces an Either

Returns a ReaderIOResult with the original value if both computations succeed.

func MonadChainFirstIOK

func MonadChainFirstIOK[A, B any](ma ReaderIOResult[A], f io.Kleisli[A, B]) ReaderIOResult[A]

MonadChainFirstIOK chains a function that returns an IO but keeps the original value. The IO computation is executed for its side effects only.

Parameters:

  • ma: The ReaderIOResult to chain from
  • f: Function that produces an IO

Returns a ReaderIOResult with the original value after executing the IO.

func MonadChainFirstLeft

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

MonadChainFirstLeft chains a computation on the left (error) side but always returns the original error. If the input is a Left value, it applies the function f to the error and executes the resulting computation, but always returns the original Left error regardless of what f returns (Left or Right). If the input is a Right value, it passes through unchanged without calling f.

This is useful for side effects on errors (like logging or metrics) where you want to perform an action when an error occurs but always propagate the original error, ensuring the error path is preserved.

func MonadChainFirstReaderIOK

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

func MonadChainFirstReaderK

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

func MonadChainFirstReaderResultK

func MonadChainFirstReaderResultK[A, B any](ma ReaderIOResult[A], f readerresult.Kleisli[A, B]) ReaderIOResult[A]

func MonadChainIOK

func MonadChainIOK[A, B any](ma ReaderIOResult[A], f io.Kleisli[A, B]) ReaderIOResult[B]

MonadChainIOK chains a function that returns an IO into a ReaderIOResult computation. The IO computation always succeeds, so it's wrapped in Right.

Parameters:

  • ma: The ReaderIOResult to chain from
  • f: Function that produces an IO

Returns a new ReaderIOResult with the chained IO computation.

func MonadChainLeft

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

MonadChainLeft chains a computation on the left (error) side of a ReaderIOResult. If the input is a Left value, it applies the function f to transform the error and potentially change the error type. If the input is a Right value, it passes through unchanged.

func MonadChainReaderIOK

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

func MonadChainReaderK

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

func MonadChainReaderResultK

func MonadChainReaderResultK[A, B any](ma ReaderIOResult[A], f readerresult.Kleisli[A, B]) ReaderIOResult[B]

func MonadFlap

func MonadFlap[B, A any](fab ReaderIOResult[func(A) B], a A) ReaderIOResult[B]

MonadFlap applies a value to a function wrapped in a ReaderIOResult. This is the reverse of MonadAp, useful in certain composition scenarios.

Parameters:

  • fab: ReaderIOResult containing a function
  • a: The value to apply to the function

Returns a ReaderIOResult with the function applied to the value.

func MonadMap

func MonadMap[A, B any](fa ReaderIOResult[A], f func(A) B) ReaderIOResult[B]

MonadMap transforms the success value of a ReaderIOResult using the provided function. If the computation fails, the error is propagated unchanged.

Parameters:

  • fa: The ReaderIOResult to transform
  • f: The transformation function

Returns a new ReaderIOResult with the transformed value.

func MonadMapTo

func MonadMapTo[A, B any](fa ReaderIOResult[A], b B) ReaderIOResult[B]

MonadMapTo replaces the success value of a ReaderIOResult with a constant value. If the computation fails, the error is propagated unchanged.

Parameters:

  • fa: The ReaderIOResult to transform
  • b: The constant value to use

Returns a new ReaderIOResult with the constant value.

func MonadTap

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

func MonadTapEitherK

func MonadTapEitherK[A, B any](ma ReaderIOResult[A], f either.Kleisli[error, A, B]) ReaderIOResult[A]

func MonadTapIOK

func MonadTapIOK[A, B any](ma ReaderIOResult[A], f io.Kleisli[A, B]) ReaderIOResult[A]

func MonadTapLeft

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

func MonadTapReaderIOK

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

func MonadTapReaderK

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

func MonadTapReaderResultK

func MonadTapReaderResultK[A, B any](ma ReaderIOResult[A], f readerresult.Kleisli[A, B]) ReaderIOResult[A]

func MonadTraverseArrayPar

func MonadTraverseArrayPar[A, B any](as []A, f Kleisli[A, B]) ReaderIOResult[[]B]

MonadTraverseArrayPar transforms an array [[]A] into [[]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[[]B]]. This explicitly uses parallel execution.

Parameters:

  • as: The array to traverse
  • f: Function that transforms each element into a ReaderIOResult

Returns a ReaderIOResult containing an array of transformed values.

func MonadTraverseArraySeq

func MonadTraverseArraySeq[A, B any](as []A, f Kleisli[A, B]) ReaderIOResult[[]B]

MonadTraverseArraySeq transforms an array [[]A] into [[]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[[]B]]. This explicitly uses sequential execution.

Parameters:

  • as: The array to traverse
  • f: Function that transforms each element into a ReaderIOResult

Returns a ReaderIOResult containing an array of transformed values.

func MonadTraverseRecordPar

func MonadTraverseRecordPar[K comparable, A, B any](as map[K]A, f Kleisli[A, B]) ReaderIOResult[map[K]B]

MonadTraverseRecordPar uses transforms a record [map[K]A] into [map[K]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[map[K]B]]

func MonadTraverseRecordSeq

func MonadTraverseRecordSeq[K comparable, A, B any](as map[K]A, f Kleisli[A, B]) ReaderIOResult[map[K]B]

MonadTraverseRecordSeq uses transforms a record [map[K]A] into [map[K]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[map[K]B]]

func Never

func Never[A any]() ReaderIOResult[A]

Never returns a ReaderIOResult that blocks indefinitely until the context is canceled. This is useful for creating computations that wait for external cancellation signals.

Returns a ReaderIOResult that waits for context cancellation and returns the cancellation error.

func Of

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

Of creates a ReaderIOResult that always succeeds with the given value. This is the same as Right and represents the monadic return operation.

Parameters:

  • a: The value to wrap

Returns a ReaderIOResult that always succeeds with the given value.

func Retrying

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

Retrying retries a ReaderIOResult computation according to a retry policy with context awareness.

This function implements a retry mechanism for operations that depend on a context.Context, perform side effects (IO), and can fail (Result). It respects context cancellation, meaning that if the context is cancelled during retry delays, the operation will stop immediately and return the cancellation error.

The retry loop will continue until one of the following occurs:

  • 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)
  • The context is cancelled (returns context.Canceled or context.DeadlineExceeded)

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[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.Context and produces a Result[A]. The context passed to the action will be the same context used for retry delays, so cancellation is properly propagated.

  • 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). Note that context cancellation errors will automatically stop retrying regardless of this function's return value.

Returns:

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

Type Parameters:

  • A: The type of the success value

Context Cancellation:

The retry mechanism respects context cancellation in two ways:

  1. During retry delays: If the context is cancelled while waiting between retries, the operation stops immediately and returns the context error.
  2. During action execution: If the action itself checks the context and returns an error due to cancellation, the retry loop will stop (assuming the check function doesn't force a retry on context errors).

Example:

// 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[string] {
    return func(ctx context.Context) IOResult[string] {
        return func() Result[string] {
            // Check if context is cancelled
            if ctx.Err() != nil {
                return result.Left[string](ctx.Err())
            }
            // Simulate an HTTP request that might fail
            if status.IterNumber < 3 {
                return result.Left[string](fmt.Errorf("temporary error"))
            }
            return result.Of("success")
        }
    }
}

// Check function: retry on any error except context cancellation
shouldRetry := func(r Result[string]) bool {
    return result.IsLeft(r) && !errors.Is(result.GetLeft(r), context.Canceled)
}

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

// Execute with a cancellable context
ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)
defer cancel()
ioResult := retryingFetch(ctx)
finalResult := ioResult()

See also:

  • retry.RetryPolicy for available retry policies
  • retry.RetryStatus for information passed to the action
  • context.Context for context cancellation semantics
func Right[A any](r A) ReaderIOResult[A]

Right creates a ReaderIOResult that represents a successful computation with the given value.

Parameters:

  • r: The success value

Returns a ReaderIOResult that always succeeds with the given value.

func SequenceArray

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

SequenceArray converts a homogeneous sequence of ReaderIOResult into a ReaderIOResult of sequence. This is equivalent to TraverseArray with the identity function.

Parameters:

  • ma: Array of ReaderIOResult values

Returns a ReaderIOResult containing an array of values.

func SequenceArrayPar

func SequenceArrayPar[A any](ma []ReaderIOResult[A]) ReaderIOResult[[]A]

SequenceArrayPar converts a homogeneous sequence of ReaderIOResult into a ReaderIOResult of sequence. This explicitly uses parallel execution.

Parameters:

  • ma: Array of ReaderIOResult values

Returns a ReaderIOResult containing an array of values.

func SequenceArraySeq

func SequenceArraySeq[A any](ma []ReaderIOResult[A]) ReaderIOResult[[]A]

SequenceArraySeq converts a homogeneous sequence of ReaderIOResult into a ReaderIOResult of sequence. This explicitly uses sequential execution.

Parameters:

  • ma: Array of ReaderIOResult values

Returns a ReaderIOResult containing an array of values.

func SequenceParT1

func SequenceParT1[T1 any](
	t1 ReaderIOResult[T1],
) ReaderIOResult[tuple.Tuple1[T1]]

SequenceParT1 converts 1 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple1[T1]]]

func SequenceParT10

func SequenceParT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
	t6 ReaderIOResult[T6],
	t7 ReaderIOResult[T7],
	t8 ReaderIOResult[T8],
	t9 ReaderIOResult[T9],
	t10 ReaderIOResult[T10],
) ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]

SequenceParT10 converts 10 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]

func SequenceParT2

func SequenceParT2[T1, T2 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
) ReaderIOResult[tuple.Tuple2[T1, T2]]

SequenceParT2 converts 2 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple2[T1, T2]]]

func SequenceParT3

func SequenceParT3[T1, T2, T3 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
) ReaderIOResult[tuple.Tuple3[T1, T2, T3]]

SequenceParT3 converts 3 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple3[T1, T2, T3]]]

func SequenceParT4

func SequenceParT4[T1, T2, T3, T4 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
) ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]

SequenceParT4 converts 4 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]]

func SequenceParT5

func SequenceParT5[T1, T2, T3, T4, T5 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
) ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]

SequenceParT5 converts 5 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]]

func SequenceParT6

func SequenceParT6[T1, T2, T3, T4, T5, T6 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
	t6 ReaderIOResult[T6],
) ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]

SequenceParT6 converts 6 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]

func SequenceParT7

func SequenceParT7[T1, T2, T3, T4, T5, T6, T7 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
	t6 ReaderIOResult[T6],
	t7 ReaderIOResult[T7],
) ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]

SequenceParT7 converts 7 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]

func SequenceParT8

func SequenceParT8[T1, T2, T3, T4, T5, T6, T7, T8 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
	t6 ReaderIOResult[T6],
	t7 ReaderIOResult[T7],
	t8 ReaderIOResult[T8],
) ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]

SequenceParT8 converts 8 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]

func SequenceParT9

func SequenceParT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
	t6 ReaderIOResult[T6],
	t7 ReaderIOResult[T7],
	t8 ReaderIOResult[T8],
	t9 ReaderIOResult[T9],
) ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]

SequenceParT9 converts 9 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]

func SequenceParTuple1

func SequenceParTuple1[T1 any](t tuple.Tuple1[ReaderIOResult[T1]]) ReaderIOResult[tuple.Tuple1[T1]]

SequenceParTuple1 converts a [tuple.Tuple1[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple1[T1]]]

func SequenceParTuple10

func SequenceParTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t tuple.Tuple10[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5], ReaderIOResult[T6], ReaderIOResult[T7], ReaderIOResult[T8], ReaderIOResult[T9], ReaderIOResult[T10]]) ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]

SequenceParTuple10 converts a [tuple.Tuple10[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]

func SequenceParTuple2

func SequenceParTuple2[T1, T2 any](t tuple.Tuple2[ReaderIOResult[T1], ReaderIOResult[T2]]) ReaderIOResult[tuple.Tuple2[T1, T2]]

SequenceParTuple2 converts a [tuple.Tuple2[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple2[T1, T2]]]

func SequenceParTuple3

func SequenceParTuple3[T1, T2, T3 any](t tuple.Tuple3[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3]]) ReaderIOResult[tuple.Tuple3[T1, T2, T3]]

SequenceParTuple3 converts a [tuple.Tuple3[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple3[T1, T2, T3]]]

func SequenceParTuple4

func SequenceParTuple4[T1, T2, T3, T4 any](t tuple.Tuple4[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4]]) ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]

SequenceParTuple4 converts a [tuple.Tuple4[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]]

func SequenceParTuple5

func SequenceParTuple5[T1, T2, T3, T4, T5 any](t tuple.Tuple5[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5]]) ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]

SequenceParTuple5 converts a [tuple.Tuple5[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]]

func SequenceParTuple6

func SequenceParTuple6[T1, T2, T3, T4, T5, T6 any](t tuple.Tuple6[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5], ReaderIOResult[T6]]) ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]

SequenceParTuple6 converts a [tuple.Tuple6[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]

func SequenceParTuple7

func SequenceParTuple7[T1, T2, T3, T4, T5, T6, T7 any](t tuple.Tuple7[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5], ReaderIOResult[T6], ReaderIOResult[T7]]) ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]

SequenceParTuple7 converts a [tuple.Tuple7[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]

func SequenceParTuple8

func SequenceParTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t tuple.Tuple8[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5], ReaderIOResult[T6], ReaderIOResult[T7], ReaderIOResult[T8]]) ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]

SequenceParTuple8 converts a [tuple.Tuple8[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]

func SequenceParTuple9

func SequenceParTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t tuple.Tuple9[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5], ReaderIOResult[T6], ReaderIOResult[T7], ReaderIOResult[T8], ReaderIOResult[T9]]) ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]

SequenceParTuple9 converts a [tuple.Tuple9[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]

func SequenceRecord

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

SequenceRecord converts a homogeneous map of ReaderIOResult into a ReaderIOResult of map.

Parameters:

  • ma: Map of ReaderIOResult values

Returns a ReaderIOResult containing a map of values.

func SequenceRecordPar

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

SequenceRecordPar converts a homogeneous map of ReaderIOResult into a ReaderIOResult of map. This explicitly uses parallel execution.

Parameters:

  • ma: Map of ReaderIOResult values

Returns a ReaderIOResult containing a map of values.

func SequenceRecordSeq

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

SequenceRecordSeq converts a homogeneous sequence of either into an either of sequence

func SequenceSeqT1

func SequenceSeqT1[T1 any](
	t1 ReaderIOResult[T1],
) ReaderIOResult[tuple.Tuple1[T1]]

SequenceSeqT1 converts 1 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple1[T1]]]

func SequenceSeqT10

func SequenceSeqT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
	t6 ReaderIOResult[T6],
	t7 ReaderIOResult[T7],
	t8 ReaderIOResult[T8],
	t9 ReaderIOResult[T9],
	t10 ReaderIOResult[T10],
) ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]

SequenceSeqT10 converts 10 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]

func SequenceSeqT2

func SequenceSeqT2[T1, T2 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
) ReaderIOResult[tuple.Tuple2[T1, T2]]

SequenceSeqT2 converts 2 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple2[T1, T2]]]

func SequenceSeqT3

func SequenceSeqT3[T1, T2, T3 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
) ReaderIOResult[tuple.Tuple3[T1, T2, T3]]

SequenceSeqT3 converts 3 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple3[T1, T2, T3]]]

func SequenceSeqT4

func SequenceSeqT4[T1, T2, T3, T4 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
) ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]

SequenceSeqT4 converts 4 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]]

func SequenceSeqT5

func SequenceSeqT5[T1, T2, T3, T4, T5 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
) ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]

SequenceSeqT5 converts 5 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]]

func SequenceSeqT6

func SequenceSeqT6[T1, T2, T3, T4, T5, T6 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
	t6 ReaderIOResult[T6],
) ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]

SequenceSeqT6 converts 6 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]

func SequenceSeqT7

func SequenceSeqT7[T1, T2, T3, T4, T5, T6, T7 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
	t6 ReaderIOResult[T6],
	t7 ReaderIOResult[T7],
) ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]

SequenceSeqT7 converts 7 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]

func SequenceSeqT8

func SequenceSeqT8[T1, T2, T3, T4, T5, T6, T7, T8 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
	t6 ReaderIOResult[T6],
	t7 ReaderIOResult[T7],
	t8 ReaderIOResult[T8],
) ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]

SequenceSeqT8 converts 8 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]

func SequenceSeqT9

func SequenceSeqT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
	t6 ReaderIOResult[T6],
	t7 ReaderIOResult[T7],
	t8 ReaderIOResult[T8],
	t9 ReaderIOResult[T9],
) ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]

SequenceSeqT9 converts 9 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]

func SequenceSeqTuple1

func SequenceSeqTuple1[T1 any](t tuple.Tuple1[ReaderIOResult[T1]]) ReaderIOResult[tuple.Tuple1[T1]]

SequenceSeqTuple1 converts a [tuple.Tuple1[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple1[T1]]]

func SequenceSeqTuple10

func SequenceSeqTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t tuple.Tuple10[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5], ReaderIOResult[T6], ReaderIOResult[T7], ReaderIOResult[T8], ReaderIOResult[T9], ReaderIOResult[T10]]) ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]

SequenceSeqTuple10 converts a [tuple.Tuple10[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]

func SequenceSeqTuple2

func SequenceSeqTuple2[T1, T2 any](t tuple.Tuple2[ReaderIOResult[T1], ReaderIOResult[T2]]) ReaderIOResult[tuple.Tuple2[T1, T2]]

SequenceSeqTuple2 converts a [tuple.Tuple2[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple2[T1, T2]]]

func SequenceSeqTuple3

func SequenceSeqTuple3[T1, T2, T3 any](t tuple.Tuple3[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3]]) ReaderIOResult[tuple.Tuple3[T1, T2, T3]]

SequenceSeqTuple3 converts a [tuple.Tuple3[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple3[T1, T2, T3]]]

func SequenceSeqTuple4

func SequenceSeqTuple4[T1, T2, T3, T4 any](t tuple.Tuple4[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4]]) ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]

SequenceSeqTuple4 converts a [tuple.Tuple4[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]]

func SequenceSeqTuple5

func SequenceSeqTuple5[T1, T2, T3, T4, T5 any](t tuple.Tuple5[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5]]) ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]

SequenceSeqTuple5 converts a [tuple.Tuple5[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]]

func SequenceSeqTuple6

func SequenceSeqTuple6[T1, T2, T3, T4, T5, T6 any](t tuple.Tuple6[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5], ReaderIOResult[T6]]) ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]

SequenceSeqTuple6 converts a [tuple.Tuple6[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]

func SequenceSeqTuple7

func SequenceSeqTuple7[T1, T2, T3, T4, T5, T6, T7 any](t tuple.Tuple7[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5], ReaderIOResult[T6], ReaderIOResult[T7]]) ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]

SequenceSeqTuple7 converts a [tuple.Tuple7[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]

func SequenceSeqTuple8

func SequenceSeqTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t tuple.Tuple8[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5], ReaderIOResult[T6], ReaderIOResult[T7], ReaderIOResult[T8]]) ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]

SequenceSeqTuple8 converts a [tuple.Tuple8[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]

func SequenceSeqTuple9

func SequenceSeqTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t tuple.Tuple9[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5], ReaderIOResult[T6], ReaderIOResult[T7], ReaderIOResult[T8], ReaderIOResult[T9]]) ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]

SequenceSeqTuple9 converts a [tuple.Tuple9[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]

func SequenceT1

func SequenceT1[T1 any](
	t1 ReaderIOResult[T1],
) ReaderIOResult[tuple.Tuple1[T1]]

SequenceT1 converts 1 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple1[T1]]]

func SequenceT10

func SequenceT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
	t6 ReaderIOResult[T6],
	t7 ReaderIOResult[T7],
	t8 ReaderIOResult[T8],
	t9 ReaderIOResult[T9],
	t10 ReaderIOResult[T10],
) ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]

SequenceT10 converts 10 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]

func SequenceT2

func SequenceT2[T1, T2 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
) ReaderIOResult[tuple.Tuple2[T1, T2]]

SequenceT2 converts 2 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple2[T1, T2]]]

func SequenceT3

func SequenceT3[T1, T2, T3 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
) ReaderIOResult[tuple.Tuple3[T1, T2, T3]]

SequenceT3 converts 3 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple3[T1, T2, T3]]]

func SequenceT4

func SequenceT4[T1, T2, T3, T4 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
) ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]

SequenceT4 converts 4 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]]

func SequenceT5

func SequenceT5[T1, T2, T3, T4, T5 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
) ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]

SequenceT5 converts 5 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]]

func SequenceT6

func SequenceT6[T1, T2, T3, T4, T5, T6 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
	t6 ReaderIOResult[T6],
) ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]

SequenceT6 converts 6 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]

func SequenceT7

func SequenceT7[T1, T2, T3, T4, T5, T6, T7 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
	t6 ReaderIOResult[T6],
	t7 ReaderIOResult[T7],
) ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]

SequenceT7 converts 7 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]

func SequenceT8

func SequenceT8[T1, T2, T3, T4, T5, T6, T7, T8 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
	t6 ReaderIOResult[T6],
	t7 ReaderIOResult[T7],
	t8 ReaderIOResult[T8],
) ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]

SequenceT8 converts 8 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]

func SequenceT9

func SequenceT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](
	t1 ReaderIOResult[T1],
	t2 ReaderIOResult[T2],
	t3 ReaderIOResult[T3],
	t4 ReaderIOResult[T4],
	t5 ReaderIOResult[T5],
	t6 ReaderIOResult[T6],
	t7 ReaderIOResult[T7],
	t8 ReaderIOResult[T8],
	t9 ReaderIOResult[T9],
) ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]

SequenceT9 converts 9 [ReaderIOResult[T]] into a [ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]

func SequenceTuple1

func SequenceTuple1[T1 any](t tuple.Tuple1[ReaderIOResult[T1]]) ReaderIOResult[tuple.Tuple1[T1]]

SequenceTuple1 converts a [tuple.Tuple1[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple1[T1]]]

func SequenceTuple10

func SequenceTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t tuple.Tuple10[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5], ReaderIOResult[T6], ReaderIOResult[T7], ReaderIOResult[T8], ReaderIOResult[T9], ReaderIOResult[T10]]) ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]

SequenceTuple10 converts a [tuple.Tuple10[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]

func SequenceTuple2

func SequenceTuple2[T1, T2 any](t tuple.Tuple2[ReaderIOResult[T1], ReaderIOResult[T2]]) ReaderIOResult[tuple.Tuple2[T1, T2]]

SequenceTuple2 converts a [tuple.Tuple2[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple2[T1, T2]]]

func SequenceTuple3

func SequenceTuple3[T1, T2, T3 any](t tuple.Tuple3[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3]]) ReaderIOResult[tuple.Tuple3[T1, T2, T3]]

SequenceTuple3 converts a [tuple.Tuple3[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple3[T1, T2, T3]]]

func SequenceTuple4

func SequenceTuple4[T1, T2, T3, T4 any](t tuple.Tuple4[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4]]) ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]

SequenceTuple4 converts a [tuple.Tuple4[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple4[T1, T2, T3, T4]]]

func SequenceTuple5

func SequenceTuple5[T1, T2, T3, T4, T5 any](t tuple.Tuple5[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5]]) ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]

SequenceTuple5 converts a [tuple.Tuple5[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple5[T1, T2, T3, T4, T5]]]

func SequenceTuple6

func SequenceTuple6[T1, T2, T3, T4, T5, T6 any](t tuple.Tuple6[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5], ReaderIOResult[T6]]) ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]

SequenceTuple6 converts a [tuple.Tuple6[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]

func SequenceTuple7

func SequenceTuple7[T1, T2, T3, T4, T5, T6, T7 any](t tuple.Tuple7[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5], ReaderIOResult[T6], ReaderIOResult[T7]]) ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]

SequenceTuple7 converts a [tuple.Tuple7[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]

func SequenceTuple8

func SequenceTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t tuple.Tuple8[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5], ReaderIOResult[T6], ReaderIOResult[T7], ReaderIOResult[T8]]) ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]

SequenceTuple8 converts a [tuple.Tuple8[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]

func SequenceTuple9

func SequenceTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t tuple.Tuple9[ReaderIOResult[T1], ReaderIOResult[T2], ReaderIOResult[T3], ReaderIOResult[T4], ReaderIOResult[T5], ReaderIOResult[T6], ReaderIOResult[T7], ReaderIOResult[T8], ReaderIOResult[T9]]) ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]

SequenceTuple9 converts a [tuple.Tuple9[ReaderIOResult[T]]] into a [ReaderIOResult[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]

func Timer

func Timer(delay time.Duration) ReaderIOResult[time.Time]

Timer returns the current time after waiting for the specified delay. This is useful for creating time-based computations.

Parameters:

  • delay: The duration to wait before returning the time

Returns a ReaderIOResult that produces the current time after the delay.

func TryCatch

func TryCatch[A any](f func(context.Context) func() (A, error)) ReaderIOResult[A]

TryCatch wraps a function that returns a tuple (value) into a ReaderIOResult. This is the standard way to convert Go error-returning functions into ReaderIOResult.

Parameters:

  • f: Function that takes a context and returns a function producing (value)

Returns a ReaderIOResult that wraps the error-returning function.

func WithContext

func WithContext[A any](ma ReaderIOResult[A]) ReaderIOResult[A]

WithContext wraps an existing ReaderIOResult and performs a context check for cancellation before delegating. This ensures that if the context is already canceled, the computation short-circuits immediately without executing the wrapped computation.

This is useful for adding cancellation awareness to computations that might not check the context themselves.

Parameters:

  • ma: The ReaderIOResult to wrap with context checking

Returns a ReaderIOResult that checks for cancellation before executing.

type ReaderOption

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

type ReaderResult

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

type Result

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

type Semigroup

type Semigroup[A any] = semigroup.Semigroup[ReaderIOResult[A]]

func AltSemigroup

func AltSemigroup[A any]() Semigroup[A]

AltSemigroup is a Semigroup that tries the first item and then the second one using an alternative. This creates a semigroup where combining two ReaderIOResult values means trying the first one, and if it fails, trying the second one. This is useful for implementing fallback behavior.

Returns a Semigroup for ReaderIOResult[A] with Alt-based combination.

Example:

sg := AltSemigroup[int]()
result := sg.Concat(
    Left[int](errors.New("first failed")),
    Right[int](42),
) // Returns Right(42)

type State added in v2.1.1

type State[S, A any] = state.State[S, A]

type Trampoline

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

type Void added in v2.2.2

type Void = function.Void

Directories

Path Synopsis
Package http provides functional HTTP client utilities built on top of ReaderIOResult monad.
Package http provides functional HTTP client utilities built on top of ReaderIOResult monad.
builder
Package builder provides utilities for building HTTP requests in a functional way using the ReaderIOResult monad.
Package builder provides utilities for building HTTP requests in a functional way using the ReaderIOResult monad.

Jump to

Keyboard shortcuts

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