readerio

package
v2.1.0 Latest Latest
Warning

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

Go to latest
Published: Jan 4, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Read

func Read[A any](r context.Context) func(ReaderIO[A]) IO[A]

Read executes a ReaderIO with a given context, returning the resulting IO. This is useful for providing the context dependency and obtaining an IO action that can be executed later.

Parameters:

  • r: The context to provide to the ReaderIO

Returns a function that converts a ReaderIO into an IO by applying the context.

func TraverseReader

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

TraverseReader applies a Reader-based transformation to a ReaderIO, introducing a new environment dependency.

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

Type transformation:

From: ReaderIO[A]
      = func(context.Context) func() A

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

To:   func(ReaderIO[A]) func(R) ReaderIO[B]
      = func(ReaderIO[A]) func(R) func(context.Context) func() B

This enables transforming values within a ReaderIO using environment-dependent logic.

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 ReaderIO[A] and returns a function from R to ReaderIO[B]

Example:

type Config struct {
    Multiplier int
}

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

// Apply TraverseReader
traversed := TraverseReader[Config, int, int](multiply)
computation := Of(10)
result := traversed(computation)

// Provide Config to get final result
cfg := Config{Multiplier: 5}
finalResult := result(cfg)(context.Background())() // Returns 50

Types

type Consumer

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

type Either

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

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 Kleisli

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

Kleisli represents a Kleisli arrow for the ReaderIO monad. It is a function that takes a value of type A and returns a ReaderIO computation that produces a value of type B.

Kleisli arrows are used for composing monadic computations and are fundamental to functional programming patterns involving effects and context.

Kleisli[A, B] is equivalent to func(A) func(context.Context) func() B

func SLog

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

SLog creates a Kleisli arrow that logs a value at Info level and passes it through unchanged. This is a convenience wrapper around SLogWithCallback with standard settings.

The value is logged with the provided message and then returned unchanged, making this useful for debugging and monitoring values in a ReaderIO computation pipeline.

Type Parameters:

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

Parameters:

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

Returns:

  • A Kleisli arrow that logs the value at Info level and returns it unchanged

Example:

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

result := pipeline(context.Background())()
// Logs: "Fetched user" value={ID:123 Name:"Alice"}
// Logs: "Extracted name" value="Alice"

func SLogWithCallback

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

SLogWithCallback creates a Kleisli arrow that logs a value with a custom logger and log level. The value is logged and then passed through unchanged, making this useful for debugging and monitoring values as they flow through a ReaderIO computation.

Type Parameters:

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

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 value and returns it unchanged

Example:

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

debugLog := SLogWithCallback[User](
    slog.LevelDebug,
    getMyLogger,
    "Processing user",
)

pipeline := F.Pipe2(
    fetchUser(123),
    Chain(debugLog),
)

func TailRec

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

TailRec implements stack-safe tail recursion for the ReaderIO monad.

This function enables recursive computations that depend on a context.Context and perform side effects, without risking stack overflow. It uses an iterative loop to execute the recursion, making it safe for deep or unbounded recursion.

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

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

Type Parameters:

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

Parameters:

  • f: A Kleisli arrow (A => ReaderIO[Trampoline[A, B]]) that controls recursion flow

Returns:

  • A Kleisli arrow (A => ReaderIO[B]) that executes the recursion safely

Example - Countdown:

countdownStep := func(n int) ReaderIO[tailrec.Trampoline[int, string]] {
    return func(ctx context.Context) IO[tailrec.Trampoline[int, string]] {
        return func() tailrec.Trampoline[int, string] {
            if n <= 0 {
                return tailrec.Land[int]("Done!")
            }
            return tailrec.Bounce[string](n - 1)
        }
    }
}

countdown := TailRec(countdownStep)
result := countdown(10)(context.Background())() // Returns "Done!"

Example - Sum with context:

type SumState struct {
    numbers []int
    total   int
}

sumStep := func(state SumState) ReaderIO[tailrec.Trampoline[SumState, int]] {
    return func(ctx context.Context) IO[tailrec.Trampoline[SumState, int]] {
        return func() tailrec.Trampoline[SumState, int] {
            if len(state.numbers) == 0 {
                return tailrec.Land[SumState](state.total)
            }
            return tailrec.Bounce[int](SumState{
                numbers: state.numbers[1:],
                total:   state.total + state.numbers[0],
            })
        }
    }
}

sum := TailRec(sumStep)
result := sum(SumState{numbers: []int{1, 2, 3, 4, 5}})(context.Background())()
// Returns 15, safe even for very large slices

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 Operator

type Operator[A, B any] = Kleisli[ReaderIO[A], B]

Operator represents a transformation from one ReaderIO computation to another. It takes a ReaderIO[A] and returns a ReaderIO[B], allowing for the composition of context-dependent, side-effectful computations.

Operators are useful for building pipelines of ReaderIO computations where each step can depend on the previous computation's result.

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

func After

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

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

func Ap

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

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

Parameters:

  • fa: ReaderIO containing a value

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

func ApPar

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

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

Parameters:

  • fa: ReaderIO containing a value

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

func ApSeq

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

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

Parameters:

  • fa: ReaderIO containing a value

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

func Chain

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

Chain sequences two ReaderIO 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 ReaderIO based on the first's result

Returns a function that sequences ReaderIO computations.

func ChainConsumer

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

ChainConsumer chains a consumer function into a ReaderIO 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 consumer is executed for its side effects, and the computation returns 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 ChainFirst

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

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

Parameters:

  • f: Function that produces the second ReaderIO

Returns a function that sequences ReaderIO computations.

func ChainFirstConsumer

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

ChainFirstConsumer chains a consumer function into a ReaderIO 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 ChainFirstIOK

func ChainFirstIOK[A, B any](f func(A) IO[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 ChainFirstReaderK

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

ChainFirstReaderK chains a function that returns a Reader but keeps the original value. This is the curried version of MonadChainFirstReaderK.

Parameters:

  • f: Function that produces a Reader

Returns a function that chains Reader-returning functions while preserving the original value.

func ChainIOK

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

ChainIOK chains a function that returns an IO into a ReaderIO 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 ChainReaderK

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

ChainReaderK chains a ReaderIO with a function that returns a Reader. This is the curried version of MonadChainReaderK.

Parameters:

  • f: Function that produces a Reader

Returns a function that chains Reader-returning functions.

func Delay

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

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

func Flap

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

Flap applies a value to a function wrapped in a ReaderIO. 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 ReaderIO function.

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 ReaderIO 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.

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 ReaderIO

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 := readerio.Local[string](func(ctx context.Context) (context.Context, context.CancelFunc) {
    newCtx := context.WithValue(ctx, userKey, "Alice")
    return newCtx, func() {} // No-op cancel
})

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

result := F.Pipe1(
    getUser,
    addUser,
)
user := result(context.Background())()  // Returns "Alice"

Timeout Example:

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

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

func Map

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

Map transforms the success value of a ReaderIO 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 ReaderIO.

func MapTo

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

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

Parameters:

  • b: The constant value to use

Returns a function that transforms a ReaderIO.

func Tap

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

Tap executes a side-effect computation but returns the original value. This is the curried version of MonadTap, an alias for ChainFirst.

Parameters:

  • f: Function that produces a side-effect ReaderIO

Returns a function that taps ReaderIO computations.

func TapIOK

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

TapIOK chains a function that returns an IO but keeps the original value. This is the curried version of MonadTapIOK, an alias for ChainFirstIOK.

Parameters:

  • f: Function that produces an IO for side effects

Returns a function that taps with IO-returning functions.

func TapReaderK

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

TapReaderK chains a function that returns a Reader but keeps the original value. This is the curried version of MonadTapReaderK, an alias for ChainFirstReaderK.

Parameters:

  • f: Function that produces a Reader for side effects

Returns a function that taps with Reader-returning functions.

func WithDeadline

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

WithDeadline adds an absolute deadline to the context for a ReaderIO 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.

Type Parameters:

  • A: The value type of the ReaderIO

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 := readerio.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,
    readerio.WithDeadline[Data](deadline),
)
data := result(context.Background())()  // Returns Data{} if past deadline

Combining with Parent Context:

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

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

func WithTimeout

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

WithTimeout adds a timeout to the context for a ReaderIO 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 ReaderIO is executed, not when WithTimeout is called. The cancel function is automatically called when the computation completes, ensuring proper cleanup.

Type Parameters:

  • A: The value type of the ReaderIO

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 := readerio.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,
    readerio.WithTimeout[Data](5*time.Second),
)
data := result(context.Background())()  // Returns Data{} after 5s timeout

Successful Example:

quickFetch := readerio.Of(Data{Value: "quick"})
result := F.Pipe1(
    quickFetch,
    readerio.WithTimeout[Data](5*time.Second),
)
data := result(context.Background())()  // Returns Data{Value: "quick"}

type Predicate added in v2.1.0

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

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

func SequenceReader

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

SequenceReader transforms a ReaderIO containing a Reader into a Reader containing a ReaderIO. This "flips" the nested structure, allowing you to provide the Reader's environment first, then get a ReaderIO that can be executed with a context.

Type transformation:

From: ReaderIO[Reader[R, A]]
      = func(context.Context) func() func(R) A

To:   Reader[R, ReaderIO[A]]
      = func(R) func(context.Context) func() A

This is useful for point-free style programming where you want to partially apply the Reader's environment before dealing with the context.

Type Parameters:

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

Parameters:

  • ma: A ReaderIO containing a Reader

Returns:

  • A Reader that produces a ReaderIO when given an environment

Example:

type Config struct {
    Timeout int
}

// A computation that produces a Reader
getMultiplier := func(ctx context.Context) IO[func(Config) int] {
    return func() func(Config) int {
        return func(cfg Config) int {
            return cfg.Timeout * 2
        }
    }
}

// Sequence it to apply Config first
sequenced := SequenceReader[Config, int](getMultiplier)
cfg := Config{Timeout: 30}
result := sequenced(cfg)(context.Background())() // Returns 60

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

func Ask

func Ask() ReaderIO[context.Context]

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

Returns a ReaderIO that produces the context.

func Bracket

func Bracket[
	A, B, ANY any](

	acquire ReaderIO[A],
	use Kleisli[A, B],
	release func(A, B) ReaderIO[ANY],
) ReaderIO[B]

Bracket ensures that a resource is properly acquired, used, and released, even if an error occurs. This implements the bracket pattern for safe resource management with ReaderIO.

The bracket pattern guarantees that:

  • The acquire action is executed first to obtain the resource
  • The use function is called with the acquired resource
  • The release function is always called with the resource and result, regardless of success or failure
  • The final result from the use function is returned

This is particularly useful for managing resources like file handles, database connections, or locks that must be cleaned up properly.

Type Parameters:

  • A: The type of the acquired resource
  • B: The type of the result produced by the use function
  • ANY: The type returned by the release function (typically ignored)

Parameters:

  • acquire: A ReaderIO that acquires the resource
  • use: A Kleisli arrow that uses the resource and produces a result
  • release: A function that releases the resource, receiving both the resource and the result

Returns:

  • A ReaderIO[B] that safely manages the resource lifecycle

Example:

// Acquire a file handle
acquireFile := func(ctx context.Context) IO[*os.File] {
    return func() *os.File {
        f, _ := os.Open("data.txt")
        return f
    }
}

// Use the file
readFile := func(f *os.File) ReaderIO[string] {
    return func(ctx context.Context) IO[string] {
        return func() string {
            data, _ := io.ReadAll(f)
            return string(data)
        }
    }
}

// Release the file
closeFile := func(f *os.File, result string) ReaderIO[any] {
    return func(ctx context.Context) IO[any] {
        return func() any {
            f.Close()
            return nil
        }
    }
}

// Safely read file with automatic cleanup
safeRead := Bracket(acquireFile, readFile, closeFile)
result := safeRead(context.Background())()

func Defer

func Defer[A any](gen Lazy[ReaderIO[A]]) ReaderIO[A]

Defer creates a ReaderIO 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 ReaderIO

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

func Flatten

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

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

Parameters:

  • rdr: The nested ReaderIO to flatten

Returns a flattened ReaderIO.

func FromIO

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

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

Parameters:

  • t: The IO to convert

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

func FromLazy

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

FromLazy converts a Lazy computation into a ReaderIO. 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 ReaderIO that executes the Lazy computation and wraps the result in Right.

func FromReader

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

FromReader converts a Reader into a ReaderIO. The Reader computation is lifted into the IO context, allowing it to be composed with other ReaderIO operations.

Parameters:

  • t: The Reader to convert

Returns a ReaderIO that executes the Reader and wraps the result in IO.

func Memoize

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

Memoize computes the value of the provided ReaderIO 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 ReaderIO to memoize

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

func MonadAp

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

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

Parameters:

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

Returns a ReaderIO with the function applied to the value.

func MonadApPar

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

MonadApPar implements parallel applicative application for ReaderIO. It executes the function and value computations in parallel where possible, potentially improving performance for independent operations.

Parameters:

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

Returns a ReaderIO with the function applied to the value.

func MonadApSeq

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

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

Parameters:

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

Returns a ReaderIO with the function applied to the value.

func MonadChain

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

MonadChain sequences two ReaderIO 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 ReaderIO
  • f: Function that produces the second ReaderIO based on the first's result

Returns a new ReaderIO representing the sequenced computation.

func MonadChainFirst

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

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

Parameters:

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

Returns a ReaderIO with the result of the first computation.

func MonadChainFirstIOK

func MonadChainFirstIOK[A, B any](ma ReaderIO[A], f func(A) IO[B]) ReaderIO[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 ReaderIO to chain from
  • f: Function that produces an IO

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

func MonadChainFirstReaderK

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

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

Parameters:

  • ma: The ReaderIO to chain from
  • f: Function that produces a Reader

Returns a ReaderIO with the original value after executing the Reader.

func MonadChainIOK

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

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

Parameters:

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

Returns a new ReaderIO with the chained IO computation.

func MonadChainReaderK

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

MonadChainReaderK chains a ReaderIO with a function that returns a Reader. The Reader is lifted into the ReaderIO context, allowing composition of Reader and ReaderIO operations.

Parameters:

  • ma: The ReaderIO to chain from
  • f: Function that produces a Reader

Returns a new ReaderIO with the chained Reader computation.

func MonadFlap

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

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

Parameters:

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

Returns a ReaderIO with the function applied to the value.

func MonadMap

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

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

Parameters:

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

Returns a new ReaderIO with the transformed value.

func MonadMapTo

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

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

Parameters:

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

Returns a new ReaderIO with the constant value.

func MonadTap

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

MonadTap executes a side-effect computation but returns the original value. This is an alias for MonadChainFirst and is useful for operations like logging or validation that should not affect the main computation flow.

Parameters:

  • ma: The ReaderIO to tap
  • f: Function that produces a side-effect ReaderIO

Returns a ReaderIO with the original value after executing the side effect.

func MonadTapIOK

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

MonadTapIOK chains a function that returns an IO but keeps the original value. This is an alias for MonadChainFirstIOK and is useful for side effects like logging.

Parameters:

  • ma: The ReaderIO to tap
  • f: Function that produces an IO for side effects

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

func MonadTapReaderK

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

MonadTapReaderK chains a function that returns a Reader but keeps the original value. This is an alias for MonadChainFirstReaderK and is useful for side effects.

Parameters:

  • ma: The ReaderIO to tap
  • f: Function that produces a Reader for side effects

Returns a ReaderIO with the original value after executing the Reader.

func Of

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

Of creates a ReaderIO 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 ReaderIO that always succeeds with the given value.

func Retrying

func Retrying[A any](
	policy retry.RetryPolicy,
	action Kleisli[retry.RetryStatus, A],
	check Predicate[A],
) ReaderIO[A]

Retrying retries a ReaderIO computation according to a retry policy.

This function implements a retry mechanism for operations that depend on a context.Context and perform side effects (IO). The retry loop continues 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 condition)

Type Parameters:

  • A: The type of the value produced by the action

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 ReaderIO[A]. This function is called on each retry attempt and receives information about the current retry state (iteration number, cumulative delay, etc.).

  • 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 conditions and successful/permanent results.

Returns:

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

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) ReaderIO[string] {
    return func(ctx context.Context) IO[string] {
        return func() string {
            // Simulate an operation that might fail
            if status.IterNumber < 3 {
                return ""  // Empty result indicates failure
            }
            return "success"
        }
    }
}

// Check function: retry if result is empty
shouldRetry := func(s string) bool {
    return s == ""
}

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

// Execute
ctx := context.Background()
result := retryingFetch(ctx)() // Returns "success" after 3 attempts

type Trampoline

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

Jump to

Keyboard shortcuts

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