Documentation
¶
Index ¶
- func Read[A any](r context.Context) func(ReaderIO[A]) IO[A]
- func TraverseReader[R, A, B any](f reader.Kleisli[R, A, B]) func(ReaderIO[A]) Kleisli[R, B]
- type Consumer
- type Either
- type IO
- type Kleisli
- type Lazy
- type Operator
- func After[R, E, A any](timestamp time.Time) Operator[A, A]
- func Ap[B, A any](fa ReaderIO[A]) Operator[func(A) B, B]
- func ApPar[B, A any](fa ReaderIO[A]) Operator[func(A) B, B]
- func ApSeq[B, A any](fa ReaderIO[A]) Operator[func(A) B, B]
- func Chain[A, B any](f Kleisli[A, B]) Operator[A, B]
- func ChainConsumer[A any](c Consumer[A]) Operator[A, struct{}]
- func ChainFirst[A, B any](f Kleisli[A, B]) Operator[A, A]
- func ChainFirstConsumer[A any](c Consumer[A]) Operator[A, A]
- func ChainFirstIOK[A, B any](f func(A) IO[B]) Operator[A, A]
- func ChainFirstReaderK[A, B any](f reader.Kleisli[context.Context, A, B]) Operator[A, A]
- func ChainIOK[A, B any](f func(A) IO[B]) Operator[A, B]
- func ChainReaderK[A, B any](f reader.Kleisli[context.Context, A, B]) Operator[A, B]
- func Delay[A any](delay time.Duration) Operator[A, A]
- func Flap[B, A any](a A) Operator[func(A) B, B]
- func Local[A any](f func(context.Context) (context.Context, context.CancelFunc)) Operator[A, A]
- func Map[A, B any](f func(A) B) Operator[A, B]
- func MapTo[A, B any](b B) Operator[A, B]
- func Tap[A, B any](f Kleisli[A, B]) Operator[A, A]
- func TapIOK[A, B any](f func(A) IO[B]) Operator[A, A]
- func TapReaderK[A, B any](f reader.Kleisli[context.Context, A, B]) Operator[A, A]
- func WithDeadline[A any](deadline time.Time) Operator[A, A]
- func WithTimeout[A any](timeout time.Duration) Operator[A, A]
- type Predicate
- type Reader
- type ReaderIO
- func Ask() ReaderIO[context.Context]
- func Bracket[A, B, ANY any](acquire ReaderIO[A], use Kleisli[A, B], release func(A, B) ReaderIO[ANY]) ReaderIO[B]
- func Defer[A any](gen Lazy[ReaderIO[A]]) ReaderIO[A]
- func Flatten[A any](rdr ReaderIO[ReaderIO[A]]) ReaderIO[A]
- func FromIO[A any](t IO[A]) ReaderIO[A]
- func FromLazy[A any](t Lazy[A]) ReaderIO[A]
- func FromReader[A any](t Reader[context.Context, A]) ReaderIO[A]
- func Memoize[A any](rdr ReaderIO[A]) ReaderIO[A]
- func MonadAp[B, A any](fab ReaderIO[func(A) B], fa ReaderIO[A]) ReaderIO[B]
- func MonadApPar[B, A any](fab ReaderIO[func(A) B], fa ReaderIO[A]) ReaderIO[B]
- func MonadApSeq[B, A any](fab ReaderIO[func(A) B], fa ReaderIO[A]) ReaderIO[B]
- func MonadChain[A, B any](ma ReaderIO[A], f Kleisli[A, B]) ReaderIO[B]
- func MonadChainFirst[A, B any](ma ReaderIO[A], f Kleisli[A, B]) ReaderIO[A]
- func MonadChainFirstIOK[A, B any](ma ReaderIO[A], f func(A) IO[B]) ReaderIO[A]
- func MonadChainFirstReaderK[A, B any](ma ReaderIO[A], f reader.Kleisli[context.Context, A, B]) ReaderIO[A]
- func MonadChainIOK[A, B any](ma ReaderIO[A], f func(A) IO[B]) ReaderIO[B]
- func MonadChainReaderK[A, B any](ma ReaderIO[A], f reader.Kleisli[context.Context, A, B]) ReaderIO[B]
- func MonadFlap[B, A any](fab ReaderIO[func(A) B], a A) ReaderIO[B]
- func MonadMap[A, B any](fa ReaderIO[A], f func(A) B) ReaderIO[B]
- func MonadMapTo[A, B any](fa ReaderIO[A], b B) ReaderIO[B]
- func MonadTap[A, B any](ma ReaderIO[A], f Kleisli[A, B]) ReaderIO[A]
- func MonadTapIOK[A, B any](ma ReaderIO[A], f func(A) IO[B]) ReaderIO[A]
- func MonadTapReaderK[A, B any](ma ReaderIO[A], f reader.Kleisli[context.Context, A, B]) ReaderIO[A]
- func Of[A any](a A) ReaderIO[A]
- func Retrying[A any](policy retry.RetryPolicy, action Kleisli[retry.RetryStatus, A], ...) ReaderIO[A]
- type Trampoline
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Read ¶
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 ¶
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 IO ¶
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 ¶
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 ¶
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 ¶
Lazy represents a deferred computation that produces a value of type A when executed. The computation is not executed until explicitly invoked.
type Operator ¶
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 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 ¶
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 ¶
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 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 ¶
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 ¶
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 ¶
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 ¶
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 Reader ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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]