Documentation
¶
Overview ¶
Package readerreaderioresult provides a functional programming abstraction that combines four powerful concepts: Reader, Reader, IO, and Result (Either[error, A]) monads in a nested structure. This is a specialized version of readerreaderioeither where the error type is fixed to `error` and the inner context is fixed to `context.Context`.
Type Definition ¶
ReaderReaderIOResult[R, A] is defined as:
type ReaderReaderIOResult[R, A] = ReaderReaderIOEither[R, context.Context, error, A]
Which expands to:
func(R) func(context.Context) func() Either[error, A]
This represents a computation that:
- Takes an outer environment/context of type R
- Returns a function that takes a context.Context
- Returns an IO operation (a thunk/function with no parameters)
- Produces an Either[error, A] (Result[A]) when executed
Type Parameter Ordering Convention ¶
This package follows a consistent convention for ordering type parameters in function signatures. The general rule is: R -> C -> E -> T (outer context, inner context, error, type), where:
- R: The outer Reader context/environment type
- C: The inner Reader context/environment type (for the ReaderIOEither)
- E: The Either error type
- T: The value type(s) (A, B, etc.)
However, when some type parameters can be automatically inferred by the Go compiler from function arguments, the convention is modified to minimize explicit type annotations:
Rule: Undetectable types come first, followed by detectable types, while preserving the relative order within each group (R -> C -> E -> T).
Examples:
All types detectable from first argument: MonadMap[R, C, E, A, B](fa ReaderReaderIOEither[R, C, E, A], f func(A) B) - R, C, E, A are detectable from fa - B is detectable from f - Order: R, C, E, A, B (standard order, all detectable)
Some types undetectable: FromReader[C, E, R, A](ma Reader[R, A]) ReaderReaderIOEither[R, C, E, A] - R, A are detectable from ma - C, E are undetectable (not in any argument) - Order: C, E, R, A (C, E first as undetectable, then R, A in standard order)
Multiple undetectable types: Local[C, E, A, R1, R2](f func(R2) R1) func(ReaderReaderIOEither[R1, C, E, A]) ReaderReaderIOEither[R2, C, E, A] - C, E, A are undetectable - R1, R2 are detectable from f - Order: C, E, A, R1, R2 (undetectable first, then detectable)
Functions returning Kleisli arrows: ChainReaderOptionK[R, C, A, B, E](onNone Lazy[E]) func(readeroption.Kleisli[R, A, B]) Operator[R, C, E, A, B] - Canonical order would be R, C, E, A, B - E is detectable from onNone parameter - R, C, A, B are not detectable (they're in the Kleisli argument type) - Order: R, C, A, B, E (undetectable R, C, A, B first, then detectable E)
This convention allows for more ergonomic function calls:
// Without convention - need to specify all types: result := FromReader[OuterCtx, InnerCtx, error, User](readerFunc) // With convention - only specify undetectable types: result := FromReader[InnerCtx, error](readerFunc) // R and A inferred from readerFunc
The reasoning behind this approach is to reduce the number of explicit type parameters that developers need to specify when calling functions, improving code readability and reducing verbosity while maintaining type safety.
Additional examples demonstrating the convention:
FromReaderOption[R, C, A, E](onNone Lazy[E]) Kleisli[R, C, E, ReaderOption[R, A], A] - Canonical order would be R, C, E, A - E is detectable from onNone parameter - R, C, A are not detectable (they're in the return type's Kleisli) - Order: R, C, A, E (undetectable R, C, A first, then detectable E)
MapLeft[R, C, A, E1, E2](f func(E1) E2) func(ReaderReaderIOEither[R, C, E1, A]) ReaderReaderIOEither[R, C, E2, A] - Canonical order would be R, C, E1, E2, A - E1, E2 are detectable from f parameter - R, C, A are not detectable (they're in the return type) - Order: R, C, A, E1, E2 (undetectable R, C, A first, then detectable E1, E2)
Additional special cases:
- Ap[B, R, C, E, A]: B is undetectable (in function return type), so B comes first
- ChainOptionK[R, C, A, B, E]: R, C, A, B are undetectable, E is detectable from onNone
- FromReaderIO[C, E, R, A]: C, E are undetectable, R, A are detectable from ReaderIO[R, A]
All functions in this package follow this convention consistently.
Fantasy Land Specification ¶
This is a monad transformer combining:
- Reader monad: https://github.com/fantasyland/fantasy-land
- Reader monad (nested): https://github.com/fantasyland/fantasy-land
- IO monad: https://github.com/fantasyland/fantasy-land
- Either monad: https://github.com/fantasyland/fantasy-land#either
Implemented Fantasy Land algebras:
- Functor: https://github.com/fantasyland/fantasy-land#functor
- Bifunctor: https://github.com/fantasyland/fantasy-land#bifunctor
- Apply: https://github.com/fantasyland/fantasy-land#apply
- Applicative: https://github.com/fantasyland/fantasy-land#applicative
- Chain: https://github.com/fantasyland/fantasy-land#chain
- Monad: https://github.com/fantasyland/fantasy-land#monad
- Alt: https://github.com/fantasyland/fantasy-land#alt
ReaderReaderIOEither ¶
ReaderReaderIOEither[R, C, E, A] represents a computation that:
- Depends on an outer context/environment of type R (outer Reader)
- Returns a computation that depends on an inner context/environment of type C (inner Reader)
- Performs side effects (IO)
- Can fail with an error of type E or succeed with a value of type A (Either)
This is particularly useful for:
- Multi-level dependency injection patterns
- Layered architectures with different context requirements at each layer
- Composing operations that need access to multiple levels of configuration or context
- Building reusable components that can be configured at different stages
Core Operations ¶
Construction:
- Of/Right: Create a successful computation
- Left: Create a failed computation
- FromEither: Lift an Either into ReaderReaderIOEither
- FromIO: Lift an IO into ReaderReaderIOEither
- FromReader: Lift a Reader into ReaderReaderIOEither
- FromReaderIO: Lift a ReaderIO into ReaderReaderIOEither
- FromIOEither: Lift an IOEither into ReaderReaderIOEither
- FromReaderEither: Lift a ReaderEither into ReaderReaderIOEither
- FromReaderIOEither: Lift a ReaderIOEither into ReaderReaderIOEither
- FromReaderOption: Lift a ReaderOption into ReaderReaderIOEither
Transformation:
- Map: Transform the success value
- MapLeft: Transform the error value
- Chain/Bind: Sequence dependent computations
- Flatten: Flatten nested ReaderReaderIOEither
Combination:
- Ap: Apply a function in a context to a value in a context
- ApSeq: Sequential application
- ApPar: Parallel application
Error Handling:
- Alt: Choose the first successful computation
Context Access:
- Ask: Get the current outer context
- Asks: Get a value derived from the outer context
- Local: Run a computation with a modified outer context
- Read: Execute with a specific outer context
Kleisli Composition:
- ChainEitherK: Chain with Either-returning functions
- ChainReaderK: Chain with Reader-returning functions
- ChainReaderIOK: Chain with ReaderIO-returning functions
- ChainReaderEitherK: Chain with ReaderEither-returning functions
- ChainReaderOptionK: Chain with ReaderOption-returning functions
- ChainIOEitherK: Chain with IOEither-returning functions
- ChainIOK: Chain with IO-returning functions
- ChainOptionK: Chain with Option-returning functions
First/Tap Operations (execute for side effects, return original value):
- ChainFirst/Tap: Execute a computation but return the original value
- ChainFirstEitherK/TapEitherK: Tap with Either-returning functions
- ChainFirstReaderK/TapReaderK: Tap with Reader-returning functions
- ChainFirstReaderIOK/TapReaderIOK: Tap with ReaderIO-returning functions
- ChainFirstReaderEitherK/TapReaderEitherK: Tap with ReaderEither-returning functions
- ChainFirstReaderOptionK/TapReaderOptionK: Tap with ReaderOption-returning functions
- ChainFirstIOK/TapIOK: Tap with IO-returning functions
Example Usage ¶
type AppConfig struct {
DatabaseURL string
LogLevel string
}
// A computation that depends on AppConfig and context.Context
func fetchUser(id int) ReaderReaderIOResult[AppConfig, User] {
return func(cfg AppConfig) readerioresult.ReaderIOResult[context.Context, User] {
// Use cfg.DatabaseURL and cfg.LogLevel
return func(ctx context.Context) ioresult.IOResult[User] {
// Use ctx for cancellation/timeout
return func() result.Result[User] {
// Perform the actual IO operation
// Return result.Of(user) or result.Error[User](err)
}
}
}
}
// Compose operations
result := function.Pipe2(
fetchUser(123),
Map[AppConfig](func(u User) string { return u.Name }),
Chain[AppConfig](func(name string) ReaderReaderIOResult[AppConfig, string] {
return Of[AppConfig]("Hello, " + name)
}),
)
// Execute with config and context
appConfig := AppConfig{DatabaseURL: "postgres://...", LogLevel: "info"}
ctx := t.Context()
outcome := result(appConfig)(ctx)() // Returns result.Result[string]
Use Cases ¶
This monad is particularly useful for:
- Applications with layered configuration (app config + request context)
- HTTP handlers that need both application config and request context
- Database operations with connection pool config and query context
- Retry logic with policy configuration and execution context
- Resource management with bracket pattern across multiple contexts
Dependency Injection with the Outer Context ¶
The outer Reader context (type parameter R) provides a powerful mechanism for dependency injection in functional programming. This pattern is explained in detail in Scott Wlaschin's talk: "Dependency Injection, The Functional Way" - https://www.youtube.com/watch?v=xPlsVVaMoB0
## Core Concept
Instead of using traditional OOP dependency injection frameworks, the Reader monad allows you to:
- Define functions that declare their dependencies as type parameters
- Compose these functions without providing the dependencies
- Supply all dependencies at the "end of the world" (program entry point)
This approach provides:
- Compile-time safety: Missing dependencies cause compilation errors
- Explicit dependencies: Function signatures show exactly what they need
- Easy testing: Mock dependencies by providing different values
- Pure functions: Dependencies are passed as parameters, not global state
## Examples from the Video Adapted to fp-go
### Example 1: Basic Reader Pattern (Video: "Reader Monad Basics")
In the video, Scott shows how to pass configuration through a chain of functions. In fp-go with ReaderReaderIOResult:
// Define your dependencies
type AppConfig struct {
DatabaseURL string
APIKey string
MaxRetries int
}
// Functions declare their dependencies via the R type parameter
func getConnectionString() ReaderReaderIOResult[AppConfig, string] {
return Asks[AppConfig](func(cfg AppConfig) string {
return cfg.DatabaseURL
})
}
func connectToDatabase() ReaderReaderIOResult[AppConfig, *sql.DB] {
return MonadChain(
getConnectionString(),
func(connStr string) ReaderReaderIOResult[AppConfig, *sql.DB] {
return FromIO[AppConfig](func() result.Result[*sql.DB] {
db, err := sql.Open("postgres", connStr)
return result.FromEither(either.FromError(db, err))
})
},
)
}
### Example 2: Composing Dependencies (Video: "Composing Reader Functions")
The video demonstrates how Reader functions compose naturally. In fp-go, you can compose operations that all share the same dependency:
func fetchUser(id int) ReaderReaderIOResult[AppConfig, User] {
return MonadChain(
connectToDatabase(),
func(db *sql.DB) ReaderReaderIOResult[AppConfig, User] {
return FromIO[AppConfig](func() result.Result[User] {
// Query database using db and return user
// The AppConfig is still available if needed
})
},
)
}
func enrichUser(user User) ReaderReaderIOResult[AppConfig, EnrichedUser] {
return Asks[AppConfig, EnrichedUser](func(cfg AppConfig) EnrichedUser {
// Use cfg.APIKey to call external service
return EnrichedUser{User: user, Extra: "data"}
})
}
// Compose without providing dependencies
pipeline := function.Pipe2(
fetchUser(123),
Chain[AppConfig](enrichUser),
)
// Provide dependencies at the end
config := AppConfig{DatabaseURL: "...", APIKey: "...", MaxRetries: 3}
ctx := context.Background()
result := pipeline(config)(ctx)()
### Example 3: Local Context Modification (Video: "Local Environment")
The video shows how to temporarily modify the environment for a sub-computation. In fp-go, use the Local function:
// Run a computation with modified configuration
func withRetries(retries int, action ReaderReaderIOResult[AppConfig, string]) ReaderReaderIOResult[AppConfig, string] {
return Local[string](func(cfg AppConfig) AppConfig {
// Create a modified config with different retry count
return AppConfig{
DatabaseURL: cfg.DatabaseURL,
APIKey: cfg.APIKey,
MaxRetries: retries,
}
})(action)
}
// Use it
result := withRetries(5, fetchUser(123))
### Example 4: Testing with Mock Dependencies (Video: "Testing with Reader")
The video emphasizes how Reader makes testing easy by allowing mock dependencies. In fp-go:
func TestFetchUser(t *testing.T) {
// Create a test configuration
testConfig := AppConfig{
DatabaseURL: "mock://test",
APIKey: "test-key",
MaxRetries: 1,
}
// Run the computation with test config
ctx := context.Background()
result := fetchUser(123)(testConfig)(ctx)()
// Assert on the result
assert.True(t, either.IsRight(result))
}
### Example 5: Multi-Layer Dependencies (Video: "Nested Readers")
The video discusses nested readers for multi-layer architectures. ReaderReaderIOResult provides exactly this with R (outer) and context.Context (inner):
type AppConfig struct {
DatabaseURL string
}
// Outer context: Application-level configuration (AppConfig)
// Inner context: Request-level context (context.Context)
func handleRequest(userID int) ReaderReaderIOResult[AppConfig, Response] {
return func(cfg AppConfig) readerioresult.ReaderIOResult[context.Context, Response] {
// cfg is available here (outer context)
return func(ctx context.Context) ioresult.IOResult[Response] {
// ctx is available here (inner context)
// Both cfg and ctx can be used
return func() result.Result[Response] {
// Perform operation using both contexts
select {
case <-ctx.Done():
return result.Error[Response](ctx.Err())
default:
// Use cfg.DatabaseURL to connect
return result.Of(Response{})
}
}
}
}
}
### Example 6: Avoiding Global State (Video: "Problems with Global State")
The video criticizes global state and shows how Reader solves this. In fp-go, instead of:
// BAD: Global state
var globalConfig AppConfig
func fetchUser(id int) result.Result[User] {
// Uses globalConfig implicitly
db := connectTo(globalConfig.DatabaseURL)
// ...
}
Use Reader to make dependencies explicit:
// GOOD: Explicit dependencies
func fetchUser(id int) ReaderReaderIOResult[AppConfig, User] {
return MonadChain(
Ask[AppConfig](), // Explicitly request the config
func(cfg AppConfig) ReaderReaderIOResult[AppConfig, User] {
// Use cfg explicitly
return FromIO[AppConfig](func() result.Result[User] {
db := connectTo(cfg.DatabaseURL)
// ...
})
},
)
}
## Benefits of This Approach
1. **Type Safety**: The compiler ensures all dependencies are provided 2. **Testability**: Easy to provide mock dependencies for testing 3. **Composability**: Functions compose naturally without dependency wiring 4. **Explicitness**: Function signatures document their dependencies 5. **Immutability**: Dependencies are immutable values, not mutable global state 6. **Flexibility**: Use Local to modify dependencies for sub-computations 7. **Separation of Concerns**: Business logic is separate from dependency resolution
## Comparison with Traditional DI
Traditional OOP DI (e.g., Spring, Guice):
- Runtime dependency resolution
- Magic/reflection-based wiring
- Implicit dependencies (hidden in constructors)
- Mutable containers
Reader-based DI (fp-go):
- Compile-time dependency resolution
- Explicit function composition
- Explicit dependencies (in type signatures)
- Immutable values
## When to Use Each Layer
- **Outer Reader (R)**: Application-level dependencies that rarely change
- Database connection pools
- API keys and secrets
- Feature flags
- Application configuration
- **Inner Reader (context.Context)**: Request-level dependencies that change per operation
- Request IDs and tracing
- Cancellation signals
- Deadlines and timeouts
- User authentication tokens
This two-layer approach mirrors the video's discussion of nested readers and provides a clean separation between application-level and request-level concerns.
Relationship to Other Packages ¶
- readerreaderioeither: The generic version with configurable error and context types
- readerioresult: Single reader with context.Context and error
- readerresult: Single reader with error (no IO)
- context/readerioresult: Alias for readerioresult with context.Context
Copyright (c) 2025 IBM Corp. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
Index ¶
- func ChainFirstReaderOptionK[R, A, B any](onNone Lazy[error]) func(readeroption.Kleisli[R, A, B]) Operator[R, A, A]
- func ChainLeft[R, A any](f Kleisli[R, error, A]) func(ReaderReaderIOResult[R, A]) ReaderReaderIOResult[R, A]
- func ChainOptionK[R, A, B any](onNone Lazy[error]) func(option.Kleisli[A, B]) Operator[R, A, B]
- func ChainReaderOptionK[R, A, B any](onNone Lazy[error]) func(readeroption.Kleisli[R, A, B]) Operator[R, A, B]
- func FromOption[R, A any](onNone Lazy[error]) func(Option[A]) ReaderReaderIOResult[R, A]
- func Local[A, R1, R2 any](f func(R2) R1) func(ReaderReaderIOResult[R1, A]) ReaderReaderIOResult[R2, A]
- func Read[A, R any](r R) func(ReaderReaderIOResult[R, A]) ReaderIOResult[context.Context, A]
- func ReadIO[A, R any](rio IO[R]) func(ReaderReaderIOResult[R, A]) ReaderIOResult[context.Context, A]
- func ReadIOEither[A, R any](rio IOEither[error, R]) func(ReaderReaderIOResult[R, A]) ReaderIOResult[context.Context, A]
- func TapReaderOptionK[R, A, B any](onNone Lazy[error]) func(readeroption.Kleisli[R, A, B]) Operator[R, A, A]
- func Traverse[R2, R1, A, B any](f Kleisli[R1, A, B]) func(ReaderReaderIOResult[R2, A]) Kleisli[R2, R1, B]
- func TraverseReader[R2, R1, A, B any](f reader.Kleisli[R1, A, B]) func(ReaderReaderIOResult[R2, A]) Kleisli[R2, R1, B]
- type Either
- type Endmorphism
- type IO
- type IOEither
- type IOResult
- type Kleisli
- func FromPredicate[R, A any](pred func(A) bool, onFalse func(A) error) Kleisli[R, A, A]
- func FromReaderOption[R, A any](onNone Lazy[error]) Kleisli[R, ReaderOption[R, A], A]
- func Sequence[R1, R2, A any](ma ReaderReaderIOResult[R2, ReaderReaderIOResult[R1, A]]) Kleisli[R2, R1, A]
- func SequenceReader[R1, R2, A any](ma ReaderReaderIOResult[R2, Reader[R1, A]]) Kleisli[R2, R1, A]
- func SequenceReaderIO[R1, R2, A any](ma ReaderReaderIOResult[R2, ReaderIO[R1, A]]) Kleisli[R2, R1, A]
- type Lazy
- type Lens
- type Monoid
- func AltMonoid[R, A any](zero Lazy[ReaderReaderIOResult[R, A]]) Monoid[R, A]
- func AlternativeMonoid[R, A any](m monoid.Monoid[A]) Monoid[R, A]
- func ApplicativeMonoid[R, A any](m monoid.Monoid[A]) Monoid[R, A]
- func ApplicativeMonoidPar[R, A any](m monoid.Monoid[A]) Monoid[R, A]
- func ApplicativeMonoidSeq[R, A any](m monoid.Monoid[A]) Monoid[R, A]
- type Operator
- func Alt[R, A any](second Lazy[ReaderReaderIOResult[R, A]]) Operator[R, A, A]
- func Ap[B, R, A any](fa ReaderReaderIOResult[R, A]) Operator[R, func(A) B, B]
- func ApEitherS[R, S1, S2, T any](setter func(T) func(S1) S2, fa Either[error, T]) Operator[R, S1, S2]
- func ApEitherSL[R, S, T any](lens Lens[S, T], fa Either[error, T]) Operator[R, S, S]
- func ApIOEitherS[R, S1, S2, T any](setter func(T) func(S1) S2, fa IOEither[error, T]) Operator[R, S1, S2]
- func ApIOEitherSL[R, S, T any](lens Lens[S, T], fa IOEither[error, T]) Operator[R, S, S]
- func ApIOS[R, S1, S2, T any](setter func(T) func(S1) S2, fa IO[T]) Operator[R, S1, S2]
- func ApIOSL[R, S, T any](lens Lens[S, T], fa IO[T]) Operator[R, S, S]
- func ApReaderIOS[R, S1, S2, T any](setter func(T) func(S1) S2, fa ReaderIO[R, T]) Operator[R, S1, S2]
- func ApReaderIOSL[R, S, T any](lens Lens[S, T], fa ReaderIO[R, T]) Operator[R, S, S]
- func ApReaderS[R, S1, S2, T any](setter func(T) func(S1) S2, fa Reader[R, T]) Operator[R, S1, S2]
- func ApReaderSL[R, S, T any](lens Lens[S, T], fa Reader[R, T]) Operator[R, S, S]
- func ApS[R, S1, S2, T any](setter func(T) func(S1) S2, fa ReaderReaderIOResult[R, T]) Operator[R, S1, S2]
- func ApSL[R, S, T any](lens Lens[S, T], fa ReaderReaderIOResult[R, T]) Operator[R, S, S]
- func Bind[R, S1, S2, T any](setter func(T) func(S1) S2, f func(S1) ReaderReaderIOResult[R, T]) Operator[R, S1, S2]
- func BindEitherK[R, S1, S2, T any](setter func(T) func(S1) S2, f either.Kleisli[error, S1, T]) Operator[R, S1, S2]
- func BindIOEitherK[R, S1, S2, T any](setter func(T) func(S1) S2, f ioeither.Kleisli[error, S1, T]) Operator[R, S1, S2]
- func BindIOEitherKL[R, S, T any](lens Lens[S, T], f ioeither.Kleisli[error, T, T]) Operator[R, S, S]
- func BindIOK[R, S1, S2, T any](setter func(T) func(S1) S2, f io.Kleisli[S1, T]) Operator[R, S1, S2]
- func BindIOKL[R, S, T any](lens Lens[S, T], f io.Kleisli[T, T]) Operator[R, S, S]
- func BindIOResultK[R, S1, S2, T any](setter func(T) func(S1) S2, f ioresult.Kleisli[S1, T]) Operator[R, S1, S2]
- func BindL[R, S, T any](lens Lens[S, T], f func(T) ReaderReaderIOResult[R, T]) Operator[R, S, S]
- func BindReaderIOK[R, S1, S2, T any](setter func(T) func(S1) S2, f readerio.Kleisli[R, S1, T]) Operator[R, S1, S2]
- func BindReaderIOKL[R, S, T any](lens Lens[S, T], f readerio.Kleisli[R, T, T]) Operator[R, S, S]
- func BindReaderK[R, S1, S2, T any](setter func(T) func(S1) S2, f reader.Kleisli[R, S1, T]) Operator[R, S1, S2]
- func BindReaderKL[R, S, T any](lens Lens[S, T], f reader.Kleisli[R, T, T]) Operator[R, S, S]
- func BindTo[R, S1, T any](setter func(T) S1) Operator[R, T, S1]
- func Chain[R, A, B any](f Kleisli[R, A, B]) Operator[R, A, B]
- func ChainEitherK[R, A, B any](f either.Kleisli[error, A, B]) Operator[R, A, B]
- func ChainFirst[R, A, B any](f Kleisli[R, A, B]) Operator[R, A, A]
- func ChainFirstEitherK[R, A, B any](f either.Kleisli[error, A, B]) Operator[R, A, A]
- func ChainFirstIOK[R, A, B any](f io.Kleisli[A, B]) Operator[R, A, A]
- func ChainFirstReaderEitherK[R, A, B any](f RE.Kleisli[R, error, A, B]) Operator[R, A, A]
- func ChainFirstReaderIOK[R, A, B any](f readerio.Kleisli[R, A, B]) Operator[R, A, A]
- func ChainFirstReaderK[R, A, B any](f reader.Kleisli[R, A, B]) Operator[R, A, A]
- func ChainIOEitherK[R, A, B any](f IOE.Kleisli[error, A, B]) Operator[R, A, B]
- func ChainIOK[R, A, B any](f io.Kleisli[A, B]) Operator[R, A, B]
- func ChainReaderEitherK[R, A, B any](f RE.Kleisli[R, error, A, B]) Operator[R, A, B]
- func ChainReaderIOK[R, A, B any](f readerio.Kleisli[R, A, B]) Operator[R, A, B]
- func ChainReaderK[R, A, B any](f reader.Kleisli[R, A, B]) Operator[R, A, B]
- func Delay[R, A any](delay time.Duration) Operator[R, A, A]
- func Flap[R, B, A any](a A) Operator[R, func(A) B, B]
- func Let[R, S1, S2, T any](setter func(T) func(S1) S2, f func(S1) T) Operator[R, S1, S2]
- func LetL[R, S, T any](lens Lens[S, T], f func(T) T) Operator[R, S, S]
- func LetTo[R, S1, S2, T any](setter func(T) func(S1) S2, b T) Operator[R, S1, S2]
- func LetToL[R, S, T any](lens Lens[S, T], b T) Operator[R, S, S]
- func Map[R, A, B any](f func(A) B) Operator[R, A, B]
- func MapLeft[R, A any](f Endmorphism[error]) Operator[R, A, A]
- func MapTo[R, A, B any](b B) Operator[R, A, B]
- func Tap[R, A, B any](f Kleisli[R, A, B]) Operator[R, A, A]
- func TapEitherK[R, A, B any](f either.Kleisli[error, A, B]) Operator[R, A, A]
- func TapIOK[R, A, B any](f io.Kleisli[A, B]) Operator[R, A, A]
- func TapReaderEitherK[R, A, B any](f RE.Kleisli[R, error, A, B]) Operator[R, A, A]
- func TapReaderIOK[R, A, B any](f readerio.Kleisli[R, A, B]) Operator[R, A, A]
- func TapReaderK[R, A, B any](f reader.Kleisli[R, A, B]) Operator[R, A, A]
- type Option
- type Predicate
- type Reader
- type ReaderIO
- type ReaderIOResult
- type ReaderOption
- type ReaderReaderIOEither
- type ReaderReaderIOResult
- func Ask[R any]() ReaderReaderIOResult[R, R]
- func Asks[R, A any](r Reader[R, A]) ReaderReaderIOResult[R, A]
- func Bracket[R, A, B, ANY any](acquire ReaderReaderIOResult[R, A], use Kleisli[R, A, B], ...) ReaderReaderIOResult[R, B]
- func Do[R, S any](empty S) ReaderReaderIOResult[R, S]
- func Flatten[R, A any](mma ReaderReaderIOResult[R, ReaderReaderIOResult[R, A]]) ReaderReaderIOResult[R, A]
- func FromEither[R, A any](t Either[error, A]) ReaderReaderIOResult[R, A]
- func FromIO[R, A any](ma IO[A]) ReaderReaderIOResult[R, A]
- func FromIOEither[R, A any](ma IOEither[error, A]) ReaderReaderIOResult[R, A]
- func FromIOResult[R, A any](ma IOResult[A]) ReaderReaderIOResult[R, A]
- func FromReader[R, A any](ma Reader[R, A]) ReaderReaderIOResult[R, A]
- func FromReaderEither[R, A any](ma RE.ReaderEither[R, error, A]) ReaderReaderIOResult[R, A]
- func FromReaderIO[R, A any](ma ReaderIO[R, A]) ReaderReaderIOResult[R, A]
- func FromReaderIOResult[R, A any](ma ReaderIOResult[R, A]) ReaderReaderIOResult[R, A]
- func FromResult[R, A any](t Result[A]) ReaderReaderIOResult[R, A]
- func Left[R, A any](e error) ReaderReaderIOResult[R, A]
- func LeftIO[R, A any](ma IO[error]) ReaderReaderIOResult[R, A]
- func LeftReader[A, R any](ma Reader[R, error]) ReaderReaderIOResult[R, A]
- func LeftReaderIO[A, R any](me ReaderIO[R, error]) ReaderReaderIOResult[R, A]
- func MonadAlt[R, A any](first ReaderReaderIOResult[R, A], second Lazy[ReaderReaderIOResult[R, A]]) ReaderReaderIOResult[R, A]
- func MonadAp[R, A, B any](fab ReaderReaderIOResult[R, func(A) B], fa ReaderReaderIOResult[R, A]) ReaderReaderIOResult[R, B]
- func MonadApPar[R, A, B any](fab ReaderReaderIOResult[R, func(A) B], fa ReaderReaderIOResult[R, A]) ReaderReaderIOResult[R, B]
- func MonadApSeq[R, A, B any](fab ReaderReaderIOResult[R, func(A) B], fa ReaderReaderIOResult[R, A]) ReaderReaderIOResult[R, B]
- func MonadChain[R, A, B any](fa ReaderReaderIOResult[R, A], f Kleisli[R, A, B]) ReaderReaderIOResult[R, B]
- func MonadChainEitherK[R, A, B any](ma ReaderReaderIOResult[R, A], f either.Kleisli[error, A, B]) ReaderReaderIOResult[R, B]
- func MonadChainFirst[R, A, B any](fa ReaderReaderIOResult[R, A], f Kleisli[R, A, B]) ReaderReaderIOResult[R, A]
- func MonadChainFirstEitherK[R, A, B any](ma ReaderReaderIOResult[R, A], f either.Kleisli[error, A, B]) ReaderReaderIOResult[R, A]
- func MonadChainFirstIOK[R, A, B any](ma ReaderReaderIOResult[R, A], f io.Kleisli[A, B]) ReaderReaderIOResult[R, A]
- func MonadChainFirstReaderEitherK[R, A, B any](ma ReaderReaderIOResult[R, A], f RE.Kleisli[R, error, A, B]) ReaderReaderIOResult[R, A]
- func MonadChainFirstReaderIOK[R, A, B any](ma ReaderReaderIOResult[R, A], f readerio.Kleisli[R, A, B]) ReaderReaderIOResult[R, A]
- func MonadChainFirstReaderK[R, A, B any](ma ReaderReaderIOResult[R, A], f reader.Kleisli[R, A, B]) ReaderReaderIOResult[R, A]
- func MonadChainIOEitherK[R, A, B any](ma ReaderReaderIOResult[R, A], f IOE.Kleisli[error, A, B]) ReaderReaderIOResult[R, B]
- func MonadChainIOK[R, A, B any](ma ReaderReaderIOResult[R, A], f io.Kleisli[A, B]) ReaderReaderIOResult[R, B]
- func MonadChainLeft[R, A any](fa ReaderReaderIOResult[R, A], f Kleisli[R, error, A]) ReaderReaderIOResult[R, A]
- func MonadChainReaderEitherK[R, A, B any](ma ReaderReaderIOResult[R, A], f RE.Kleisli[R, error, A, B]) ReaderReaderIOResult[R, B]
- func MonadChainReaderIOK[R, A, B any](ma ReaderReaderIOResult[R, A], f readerio.Kleisli[R, A, B]) ReaderReaderIOResult[R, B]
- func MonadChainReaderK[R, A, B any](ma ReaderReaderIOResult[R, A], f reader.Kleisli[R, A, B]) ReaderReaderIOResult[R, B]
- func MonadFlap[R, B, A any](fab ReaderReaderIOResult[R, func(A) B], a A) ReaderReaderIOResult[R, B]
- func MonadMap[R, A, B any](fa ReaderReaderIOResult[R, A], f func(A) B) ReaderReaderIOResult[R, B]
- func MonadMapLeft[R, A any](fa ReaderReaderIOResult[R, A], f Endmorphism[error]) ReaderReaderIOResult[R, A]
- func MonadMapTo[R, A, B any](fa ReaderReaderIOResult[R, A], b B) ReaderReaderIOResult[R, B]
- func MonadTap[R, A, B any](fa ReaderReaderIOResult[R, A], f Kleisli[R, A, B]) ReaderReaderIOResult[R, A]
- func MonadTapEitherK[R, A, B any](ma ReaderReaderIOResult[R, A], f either.Kleisli[error, A, B]) ReaderReaderIOResult[R, A]
- func MonadTapIOK[R, A, B any](ma ReaderReaderIOResult[R, A], f io.Kleisli[A, B]) ReaderReaderIOResult[R, A]
- func MonadTapReaderEitherK[R, A, B any](ma ReaderReaderIOResult[R, A], f RE.Kleisli[R, error, A, B]) ReaderReaderIOResult[R, A]
- func MonadTapReaderIOK[R, A, B any](ma ReaderReaderIOResult[R, A], f readerio.Kleisli[R, A, B]) ReaderReaderIOResult[R, A]
- func MonadTapReaderK[R, A, B any](ma ReaderReaderIOResult[R, A], f reader.Kleisli[R, A, B]) ReaderReaderIOResult[R, A]
- func Of[R, A any](a A) ReaderReaderIOResult[R, A]
- func Retrying[R, A any](policy retry.RetryPolicy, action Kleisli[R, retry.RetryStatus, A], ...) ReaderReaderIOResult[R, A]
- func Right[R, A any](a A) ReaderReaderIOResult[R, A]
- func RightIO[R, A any](ma IO[A]) ReaderReaderIOResult[R, A]
- func RightReader[R, A any](ma Reader[R, A]) ReaderReaderIOResult[R, A]
- func RightReaderIO[R, A any](ma ReaderIO[R, A]) ReaderReaderIOResult[R, A]
- type Result
- type Trampoline
- type Void
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ChainFirstReaderOptionK ¶
func ChainFirstReaderOptionK[R, A, B any](onNone Lazy[error]) func(readeroption.Kleisli[R, A, B]) Operator[R, A, A]
ChainFirstReaderOptionK chains a computation that returns a ReaderOption but preserves the original value. If the option is None, it uses the provided onNone function to generate an error. Returns a function that takes a ReaderOption Kleisli and returns an operator.
func ChainLeft ¶
func ChainLeft[R, A any](f Kleisli[R, error, A]) func(ReaderReaderIOResult[R, A]) ReaderReaderIOResult[R, A]
ChainLeft handles errors by chaining a recovery computation. If the computation fails, the error is passed to f for recovery. This is the curried version that returns an operator.
func ChainOptionK ¶
ChainOptionK chains a computation that returns an Option. If the option is None, it uses the provided onNone function to generate an error. Returns a function that takes an Option Kleisli and returns an operator.
func ChainReaderOptionK ¶
func ChainReaderOptionK[R, A, B any](onNone Lazy[error]) func(readeroption.Kleisli[R, A, B]) Operator[R, A, B]
ChainReaderOptionK chains a computation that returns a ReaderOption. If the option is None, it uses the provided onNone function to generate an error. Returns a function that takes a ReaderOption Kleisli and returns an operator.
func FromOption ¶
FromOption converts an Option to a ReaderReaderIOResult. If the option is None, it uses the provided onNone function to generate an error. Returns a function that takes an Option and returns a ReaderReaderIOResult.
func Local ¶
func Local[A, R1, R2 any](f func(R2) R1) func(ReaderReaderIOResult[R1, A]) ReaderReaderIOResult[R2, A]
Local modifies the outer environment before passing it to a computation. Useful for providing different configurations to sub-computations.
func Read ¶
Read provides a specific outer environment value to a computation. Converts ReaderReaderIOResult[R, A] to ReaderIOResult[context.Context, A].
func ReadIO ¶
func ReadIO[A, R any](rio IO[R]) func(ReaderReaderIOResult[R, A]) ReaderIOResult[context.Context, A]
ReadIO provides an outer environment value from an IO to a computation.
func ReadIOEither ¶
func ReadIOEither[A, R any](rio IOEither[error, R]) func(ReaderReaderIOResult[R, A]) ReaderIOResult[context.Context, A]
ReadIOEither provides an outer environment value from an IOEither to a computation.
func TapReaderOptionK ¶
func TapReaderOptionK[R, A, B any](onNone Lazy[error]) func(readeroption.Kleisli[R, A, B]) Operator[R, A, A]
TapReaderOptionK is an alias for ChainFirstReaderOptionK. Executes a ReaderOption-returning side effect while preserving the original value.
func Traverse ¶ added in v2.1.17
func Traverse[R2, R1, A, B any]( f Kleisli[R1, A, B], ) func(ReaderReaderIOResult[R2, A]) Kleisli[R2, R1, B]
Traverse transforms a ReaderReaderIOResult computation by applying a function that produces another ReaderReaderIOResult, effectively swapping the order of outer environment parameters.
This function is useful when you have a computation that depends on environment R2 and produces a value of type A, and you want to transform it using a function that takes A and produces a computation depending on environment R1. The result is a curried function that takes R1 first, then R2, and produces a computation with context.Context and error handling.
Type Parameters:
- R2: The outer environment type from the original computation
- R1: The inner environment type introduced by the transformation
- A: The input value type
- B: The output value type
Parameters:
- f: A Kleisli arrow that transforms A into a ReaderReaderIOResult[R1, B]
Returns:
- A function that takes a ReaderReaderIOResult[R2, A] and returns a Kleisli[R2, R1, B], which is func(R1) ReaderReaderIOResult[R2, B]
The function preserves error handling and IO effects while reordering the environment dependencies. This is the generalized version of Sequence that also applies a transformation function.
Example:
type AppConfig struct {
SystemID string
}
type UserConfig struct {
UserID int
}
// Original computation depending on AppConfig
original := Of[AppConfig](42)
// Transformation that introduces UserConfig dependency
transform := func(n int) ReaderReaderIOResult[UserConfig, string] {
return func(userCfg UserConfig) readerioresult.ReaderIOResult[context.Context, string] {
return readerioresult.Of[context.Context](fmt.Sprintf("User %d: %d", userCfg.UserID, n))
}
}
// Apply traverse to swap order and transform
traversed := Traverse[AppConfig, UserConfig, int, string](transform)(original)
// Provide UserConfig first, then AppConfig
ctx := context.Background()
result := traversed(UserConfig{UserID: 1})(AppConfig{SystemID: "sys1"})(ctx)()
func TraverseReader ¶ added in v2.1.17
func TraverseReader[R2, R1, A, B any]( f reader.Kleisli[R1, A, B], ) func(ReaderReaderIOResult[R2, A]) Kleisli[R2, R1, B]
TraverseReader transforms a ReaderReaderIOResult 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 ReaderReaderIOResult. The result allows you to provide the Reader's environment (R1) first, which then produces a ReaderReaderIOResult that depends on environment R2.
Type Parameters:
- R2: The outer environment type from the original ReaderReaderIOResult
- R1: The inner environment type introduced by the Reader transformation
- A: The input value type
- B: The output value type
Parameters:
- f: A Reader-based Kleisli arrow that transforms A to B using environment R1
Returns:
- A function that takes a ReaderReaderIOResult[R2, A] and returns a Kleisli[R2, R1, B], which is func(R1) ReaderReaderIOResult[R2, B]
The function preserves error handling and IO effects while adding the Reader environment dependency and reordering the environment parameters. This is useful when you want to introduce a pure (non-IO, non-error) environment dependency to an existing computation.
Example:
type AppConfig struct {
Timeout int
}
type UserPreferences struct {
Theme string
}
// Original computation depending on AppConfig
original := Of[AppConfig](100)
// Pure Reader transformation that introduces UserPreferences dependency
formatWithTheme := func(value int) reader.Reader[UserPreferences, string] {
return func(prefs UserPreferences) string {
return fmt.Sprintf("[%s theme] Value: %d", prefs.Theme, value)
}
}
// Apply traverse to introduce UserPreferences and swap order
traversed := TraverseReader[AppConfig, UserPreferences, int, string](formatWithTheme)(original)
// Provide UserPreferences first, then AppConfig
ctx := context.Background()
result := traversed(UserPreferences{Theme: "dark"})(AppConfig{Timeout: 30})(ctx)()
Types ¶
type Either ¶
Either represents a value that can be one of two types: Left (error) or Right (success). It's an alias for either.Either[E, A].
type Endmorphism ¶
type Endmorphism[A any] = endomorphism.Endomorphism[A]
Endmorphism represents a function from type A to type A. It's an alias for endomorphism.Endomorphism[A].
type IO ¶
IO represents a side-effecting computation that produces a value of type A. It's an alias for io.IO[A].
type IOEither ¶
IOEither represents a side-effecting computation that may fail with an error of type E or succeed with a value of type A. It's an alias for ioeither.IOEither[E, A].
type IOResult ¶
IOResult represents a side-effecting computation that may fail with an error or succeed with a value of type A. It's an alias for ioresult.IOResult[A] which is IOEither[error, A].
type Kleisli ¶
type Kleisli[R, A, B any] = Reader[A, ReaderReaderIOResult[R, B]]
Kleisli represents a function from A to a monadic value ReaderReaderIOResult[R, B]. It's used for composing monadic functions using Kleisli composition.
Type structure:
Kleisli[R, A, B] = A -> ReaderReaderIOResult[R, B]
Kleisli arrows can be composed using Chain operations to build complex data transformation pipelines.
func FromPredicate ¶
FromPredicate creates a ReaderReaderIOResult from a predicate. If the predicate returns true, the value is wrapped in Right. If false, onFalse is called to generate an error wrapped in Left.
func FromReaderOption ¶
FromReaderOption converts a ReaderOption to a ReaderReaderIOResult. If the option is None, it uses the provided onNone function to generate an error.
func Sequence ¶ added in v2.1.17
func Sequence[R1, R2, A any](ma ReaderReaderIOResult[R2, ReaderReaderIOResult[R1, A]]) Kleisli[R2, R1, A]
Sequence swaps the order of nested environment parameters in a ReaderReaderIOResult computation.
This function takes a ReaderReaderIOResult that produces another ReaderReaderIOResult and returns a Kleisli arrow that reverses the order of the outer environment parameters (R1 and R2). The result is a curried function that takes R1 first, then R2, and produces a computation with context.Context and error handling.
Type Parameters:
- R1: The first outer environment type (becomes the outermost after sequence)
- R2: The second outer environment type (becomes inner after sequence)
- A: The success value type
Parameters:
- ma: A ReaderReaderIOResult[R2, ReaderReaderIOResult[R1, A]]
Returns:
- A Kleisli[R2, R1, A], which is func(R1) ReaderReaderIOResult[R2, A]
The function preserves error handling and IO effects at all levels while reordering the outer environment dependencies. The inner context.Context layer remains unchanged.
This is particularly useful when you need to change the order in which contexts are provided to a nested computation, such as when composing operations that have different dependency orders.
Example:
type AppConfig struct {
DatabaseURL string
}
type UserPrefs struct {
Theme string
}
// Original: takes AppConfig, returns computation that may produce
// another computation depending on UserPrefs
original := func(cfg AppConfig) readerioresult.ReaderIOResult[context.Context,
ReaderReaderIOResult[UserPrefs, string]] {
return readerioresult.Of[context.Context](
Of[UserPrefs]("result"),
)
}
// Sequence swaps UserPrefs and AppConfig order
sequenced := Sequence[UserPrefs, AppConfig, string](original)
// Now provide UserPrefs first, then AppConfig
ctx := context.Background()
result := sequenced(UserPrefs{Theme: "dark"})(AppConfig{DatabaseURL: "db"})(ctx)()
func SequenceReader ¶ added in v2.1.17
func SequenceReader[R1, R2, A any](ma ReaderReaderIOResult[R2, Reader[R1, A]]) Kleisli[R2, R1, A]
SequenceReader swaps the order of environment parameters when the inner computation is a pure Reader.
This function is similar to Sequence but specialized for the case where the innermost computation is a pure Reader (without IO or error handling) rather than another ReaderReaderIOResult. It takes a ReaderReaderIOResult that produces a Reader and returns a Kleisli arrow that reverses the order of the outer environment parameters.
Type Parameters:
- R1: The first environment type (becomes outermost after sequence)
- R2: The second environment type (becomes inner after sequence)
- A: The success value type
Parameters:
- ma: A ReaderReaderIOResult[R2, Reader[R1, A]]
Returns:
- A Kleisli[R2, R1, A], which is func(R1) ReaderReaderIOResult[R2, A]
The function lifts the pure Reader computation into the ReaderIOResult context (with context.Context and error handling) while reordering the environment dependencies.
Example:
type AppConfig struct {
Multiplier int
}
type Database struct {
ConnectionString string
}
// Original: takes AppConfig, may produce a Reader[Database, int]
original := func(cfg AppConfig) readerioresult.ReaderIOResult[context.Context, reader.Reader[Database, int]] {
return readerioresult.Of[context.Context](func(db Database) int {
return len(db.ConnectionString) * cfg.Multiplier
})
}
// Sequence to provide Database first, then AppConfig
sequenced := SequenceReader[Database, AppConfig, int](original)
ctx := context.Background()
result := sequenced(Database{ConnectionString: "localhost"})(AppConfig{Multiplier: 2})(ctx)()
func SequenceReaderIO ¶ added in v2.1.17
func SequenceReaderIO[R1, R2, A any](ma ReaderReaderIOResult[R2, ReaderIO[R1, A]]) Kleisli[R2, R1, A]
SequenceReaderIO swaps the order of environment parameters when the inner computation is a ReaderIO.
This function is specialized for the case where the innermost computation is a ReaderIO (with IO effects but no error handling) rather than another ReaderReaderIOResult. It takes a ReaderReaderIOResult that produces a ReaderIO and returns a Kleisli arrow that reverses the order of the outer environment parameters.
Type Parameters:
- R1: The first environment type (becomes outermost after sequence)
- R2: The second environment type (becomes inner after sequence)
- A: The success value type
Parameters:
- ma: A ReaderReaderIOResult[R2, ReaderIO[R1, A]]
Returns:
- A Kleisli[R2, R1, A], which is func(R1) ReaderReaderIOResult[R2, A]
The function lifts the ReaderIO computation (which has IO effects but no error handling) into the ReaderIOResult context (with context.Context and error handling) while reordering the environment dependencies.
Example:
type AppConfig struct {
FilePath string
}
type Logger struct {
Level string
}
// Original: takes AppConfig, may produce a ReaderIO[Logger, string]
original := func(cfg AppConfig) readerioresult.ReaderIOResult[context.Context, readerio.ReaderIO[Logger, string]] {
return readerioresult.Of[context.Context](func(logger Logger) io.IO[string] {
return func() string {
return fmt.Sprintf("[%s] Reading from %s", logger.Level, cfg.FilePath)
}
})
}
// Sequence to provide Logger first, then AppConfig
sequenced := SequenceReaderIO[Logger, AppConfig, string](original)
ctx := context.Background()
result := sequenced(Logger{Level: "INFO"})(AppConfig{FilePath: "/data"})(ctx)()
type Lazy ¶
Lazy represents a lazily evaluated computation that produces a value of type A. It's an alias for lazy.Lazy[A].
type Lens ¶
Lens represents an optic for focusing on a part of a data structure. It provides a way to get and set a field T within a structure S. It's an alias for lens.Lens[S, T].
type Monoid ¶
Monoid represents a monoid structure for ReaderReaderIOResult[R, A]. A monoid provides an identity element (empty) and an associative binary operation (concat).
func AltMonoid ¶
AltMonoid creates a monoid based solely on the Alt operation. It provides a way to chain computations with fallback behavior.
The monoid:
- Uses the provided zero as the identity element
- Uses Alt for concatenation (tries first, falls back to second on failure)
- Implements a "first success" strategy
Example:
zero := func() ReaderReaderIOResult[Config, int] {
return Left[Config, int](errors.New("no value"))
}
altMonoid := AltMonoid[Config, int](zero)
// Tries computations in order until one succeeds
result := altMonoid.Concat(
Left[Config, int](errors.New("first failed")),
altMonoid.Concat(
Left[Config, int](errors.New("second failed")),
Of[Config](42),
),
) // Results in Right(42)
func AlternativeMonoid ¶
AlternativeMonoid creates a monoid that combines ReaderReaderIOResult values using both applicative composition and alternative (Alt) semantics.
This monoid:
- Uses Ap for combining successful values
- Uses Alt for handling failures (tries alternatives on failure)
- Provides a way to combine multiple computations with fallback behavior
Example:
import "github.com/IBM/fp-go/v2/monoid"
import "github.com/IBM/fp-go/v2/number"
intMonoid := AlternativeMonoid[Config](number.MonoidSum)
// If first computation fails, tries the second
result := intMonoid.Concat(
Left[Config, int](errors.New("failed")),
Of[Config](42),
) // Results in Right(42)
func ApplicativeMonoid ¶
ApplicativeMonoid creates a monoid for ReaderReaderIOResult using applicative composition. It combines values using the provided monoid m and the applicative Ap operation. This allows combining multiple ReaderReaderIOResult values in parallel while merging their results.
The resulting monoid satisfies:
- Identity: concat(empty, x) = concat(x, empty) = x
- Associativity: concat(concat(x, y), z) = concat(x, concat(y, z))
Example:
import "github.com/IBM/fp-go/v2/monoid"
import "github.com/IBM/fp-go/v2/number"
// Create a monoid for combining integers with addition
intMonoid := ApplicativeMonoid[Config](number.MonoidSum)
// Combine multiple computations
result := intMonoid.Concat(
Of[Config](10),
intMonoid.Concat(Of[Config](20), Of[Config](30)),
) // Results in 60
func ApplicativeMonoidPar ¶
ApplicativeMonoidPar creates a monoid for ReaderReaderIOResult using parallel applicative composition. Similar to ApplicativeMonoid but explicitly evaluates effects in parallel.
Use this when:
- Effects are independent and can run concurrently
- You want to maximize performance through parallelism
- Order of execution doesn't matter
func ApplicativeMonoidSeq ¶
ApplicativeMonoidSeq creates a monoid for ReaderReaderIOResult using sequential applicative composition. Similar to ApplicativeMonoid but evaluates effects sequentially rather than in parallel.
Use this when:
- Effects must be executed in a specific order
- Side effects depend on sequential execution
- You want to avoid concurrent execution
type Operator ¶
type Operator[R, A, B any] = Kleisli[R, ReaderReaderIOResult[R, A], B]
Operator is a specialized Kleisli arrow that operates on monadic values. It takes a ReaderReaderIOResult[R, A] and produces a ReaderReaderIOResult[R, B].
Type structure:
Operator[R, A, B] = ReaderReaderIOResult[R, A] -> ReaderReaderIOResult[R, B]
Operators are useful for transforming monadic computations, such as adding retry logic, logging, or error recovery.
func Alt ¶
func Alt[R, A any](second Lazy[ReaderReaderIOResult[R, A]]) Operator[R, A, A]
Alt provides alternative/fallback behavior. If the first computation fails, it tries the second (lazy-evaluated). This is the curried version that returns an operator.
func Ap ¶
func Ap[B, R, A any](fa ReaderReaderIOResult[R, A]) Operator[R, func(A) B, B]
Ap applies a function wrapped in a ReaderReaderIOResult to a value wrapped in a ReaderReaderIOResult. This is the curried version that returns an operator.
func ApEitherS ¶
func ApEitherS[R, S1, S2, T any]( setter func(T) func(S1) S2, fa Either[error, T], ) Operator[R, S1, S2]
ApEitherS applies an Either computation and attaches its result to the context.
func ApEitherSL ¶
ApEitherSL is a lens-based version of ApEitherS.
func ApIOEitherS ¶
func ApIOEitherS[R, S1, S2, T any]( setter func(T) func(S1) S2, fa IOEither[error, T], ) Operator[R, S1, S2]
ApIOEitherS applies an IOEither computation and attaches its result to the context.
func ApIOEitherSL ¶
ApIOEitherSL is a lens-based version of ApIOEitherS.
func ApIOS ¶
func ApIOS[R, S1, S2, T any]( setter func(T) func(S1) S2, fa IO[T], ) Operator[R, S1, S2]
ApIOS applies an IO computation and attaches its result to the context.
func ApIOSL ¶
func ApIOSL[R, S, T any]( lens Lens[S, T], fa IO[T], ) Operator[R, S, S]
ApIOSL is a lens-based version of ApIOS.
func ApReaderIOS ¶
func ApReaderIOS[R, S1, S2, T any]( setter func(T) func(S1) S2, fa ReaderIO[R, T], ) Operator[R, S1, S2]
ApReaderIOS applies a ReaderIO computation and attaches its result to the context.
func ApReaderIOSL ¶
func ApReaderIOSL[R, S, T any]( lens Lens[S, T], fa ReaderIO[R, T], ) Operator[R, S, S]
ApReaderIOSL is a lens-based version of ApReaderIOS.
func ApReaderS ¶
func ApReaderS[R, S1, S2, T any]( setter func(T) func(S1) S2, fa Reader[R, T], ) Operator[R, S1, S2]
ApReaderS applies a Reader computation and attaches its result to the context.
func ApReaderSL ¶
func ApReaderSL[R, S, T any]( lens Lens[S, T], fa Reader[R, T], ) Operator[R, S, S]
ApReaderSL is a lens-based version of ApReaderS.
func ApS ¶
func ApS[R, S1, S2, T any]( setter func(T) func(S1) S2, fa ReaderReaderIOResult[R, T], ) Operator[R, S1, S2]
ApS applies a computation in parallel (applicative style) and attaches its result to the context. Unlike Bind, this doesn't allow the computation to depend on the current context state.
Example:
readerreaderioeither.ApS(
func(count int) func(State) State {
return func(s State) State { s.Count = count; return s }
},
getCount, // ReaderReaderIOResult[OuterEnv, InnerEnv, error, int]
)
func ApSL ¶
func ApSL[R, S, T any]( lens Lens[S, T], fa ReaderReaderIOResult[R, T], ) Operator[R, S, S]
ApSL is a lens-based version of ApS that uses a lens to focus on a specific field in the context.
func Bind ¶
func Bind[R, S1, S2, T any]( setter func(T) func(S1) S2, f func(S1) ReaderReaderIOResult[R, T], ) Operator[R, S1, S2]
Bind attaches the result of a computation to a context [S1] to produce a context [S2]. This enables sequential composition where each step can depend on the results of previous steps and access both the outer (R) and inner (C) reader environments.
The setter function takes the result of the computation and returns a function that updates the context from S1 to S2.
Example:
type State struct {
User User
Posts []Post
}
type OuterEnv struct {
Database string
}
type InnerEnv struct {
UserRepo UserRepository
PostRepo PostRepository
}
result := F.Pipe2(
readerreaderioeither.Do[OuterEnv, InnerEnv, error](State{}),
readerreaderioeither.Bind(
func(user User) func(State) State {
return func(s State) State { s.User = user; return s }
},
func(s State) readerreaderioeither.ReaderReaderIOResult[OuterEnv, InnerEnv, error, User] {
return func(outer OuterEnv) readerioeither.ReaderIOEither[InnerEnv, error, User] {
return readerioeither.Asks(func(inner InnerEnv) ioeither.IOEither[error, User] {
return inner.UserRepo.FindUser(outer.Database)
})
}
},
),
readerreaderioeither.Bind(
func(posts []Post) func(State) State {
return func(s State) State { s.Posts = posts; return s }
},
func(s State) readerreaderioeither.ReaderReaderIOResult[OuterEnv, InnerEnv, error, []Post] {
return func(outer OuterEnv) readerioeither.ReaderIOEither[InnerEnv, error, []Post] {
return readerioeither.Asks(func(inner InnerEnv) ioeither.IOEither[error, []Post] {
return inner.PostRepo.FindPostsByUser(outer.Database, s.User.ID)
})
}
},
),
)
func BindEitherK ¶
func BindEitherK[R, S1, S2, T any]( setter func(T) func(S1) S2, f either.Kleisli[error, S1, T], ) Operator[R, S1, S2]
BindEitherK binds a computation that returns an Either to the context. The Kleisli function is automatically lifted into ReaderReaderIOResult.
func BindIOEitherK ¶
func BindIOEitherK[R, S1, S2, T any]( setter func(T) func(S1) S2, f ioeither.Kleisli[error, S1, T], ) Operator[R, S1, S2]
BindIOEitherK binds a computation that returns an IOEither to the context. The Kleisli function is automatically lifted into ReaderReaderIOResult.
func BindIOEitherKL ¶
func BindIOEitherKL[R, S, T any]( lens Lens[S, T], f ioeither.Kleisli[error, T, T], ) Operator[R, S, S]
BindIOEitherKL is a lens-based version of BindIOEitherK.
func BindIOK ¶
func BindIOK[R, S1, S2, T any]( setter func(T) func(S1) S2, f io.Kleisli[S1, T], ) Operator[R, S1, S2]
BindIOK binds a computation that returns an IO to the context. The Kleisli function is automatically lifted into ReaderReaderIOResult.
func BindIOResultK ¶
func BindL ¶
func BindL[R, S, T any]( lens Lens[S, T], f func(T) ReaderReaderIOResult[R, T], ) Operator[R, S, S]
BindL is a lens-based version of Bind that uses a lens to focus on a specific field in the context.
func BindReaderIOK ¶
func BindReaderIOK[R, S1, S2, T any]( setter func(T) func(S1) S2, f readerio.Kleisli[R, S1, T], ) Operator[R, S1, S2]
BindReaderIOK binds a computation that returns a ReaderIO to the context. The Kleisli function is automatically lifted into ReaderReaderIOResult.
func BindReaderIOKL ¶
BindReaderIOKL is a lens-based version of BindReaderIOK.
func BindReaderK ¶
func BindReaderK[R, S1, S2, T any]( setter func(T) func(S1) S2, f reader.Kleisli[R, S1, T], ) Operator[R, S1, S2]
BindReaderK binds a computation that returns a Reader to the context. The Kleisli function is automatically lifted into ReaderReaderIOResult.
func BindReaderKL ¶
BindReaderKL is a lens-based version of BindReaderK.
func BindTo ¶
func BindTo[R, S1, T any]( setter func(T) S1, ) Operator[R, T, S1]
BindTo wraps a value of type T into a context S1 using the provided setter function. This is typically used as the first operation after Do to initialize the context.
Example:
F.Pipe1(
readerreaderioeither.Of[OuterEnv, InnerEnv, error](42),
readerreaderioeither.BindTo(func(n int) State { return State{Count: n} }),
)
func Chain ¶
func Chain[R, A, B any](f Kleisli[R, A, B]) Operator[R, A, B]
Chain sequences two computations, where the second depends on the result of the first (Monad operation). This is the curried version that returns an operator.
func ChainEitherK ¶
ChainEitherK chains a computation that returns an Either. The Either is automatically lifted into ReaderReaderIOResult. This is the curried version that returns an operator.
func ChainFirst ¶
func ChainFirst[R, A, B any](f Kleisli[R, A, B]) Operator[R, A, A]
ChainFirst sequences two computations but returns the result of the first. This is the curried version that returns an operator.
func ChainFirstEitherK ¶
ChainFirstEitherK chains a computation that returns an Either but preserves the original value. This is the curried version that returns an operator.
func ChainFirstIOK ¶
ChainFirstIOK chains a computation that returns an IO but preserves the original value. This is the curried version that returns an operator.
func ChainFirstReaderEitherK ¶
ChainFirstReaderEitherK chains a computation that returns a ReaderEither but preserves the original value. This is the curried version that returns an operator.
func ChainFirstReaderIOK ¶
ChainFirstReaderIOK chains a computation that returns a ReaderIO but preserves the original value. This is the curried version that returns an operator.
func ChainFirstReaderK ¶
ChainFirstReaderK chains a computation that returns a Reader but preserves the original value. This is the curried version that returns an operator.
func ChainIOEitherK ¶
ChainIOEitherK chains a computation that returns an IOEither. The IOEither is automatically lifted into ReaderReaderIOResult. This is the curried version that returns an operator.
func ChainIOK ¶
ChainIOK chains a computation that returns an IO. The IO is automatically lifted into ReaderReaderIOResult. This is the curried version that returns an operator.
func ChainReaderEitherK ¶
ChainReaderEitherK chains a computation that returns a ReaderEither. The ReaderEither is automatically lifted into ReaderReaderIOResult. This is the curried version that returns an operator.
func ChainReaderIOK ¶
ChainReaderIOK chains a computation that returns a ReaderIO. The ReaderIO is automatically lifted into ReaderReaderIOResult. This is the curried version that returns an operator.
func ChainReaderK ¶
ChainReaderK chains a computation that returns a Reader. The Reader is automatically lifted into ReaderReaderIOResult. This is the curried version that returns an operator.
func Delay ¶
Delay adds a time delay before executing the computation. Useful for rate limiting, retry backoff, or scheduled execution.
func Flap ¶
func Flap[R, B, A any](a A) Operator[R, func(A) B, B]
Flap applies a value to a function wrapped in a ReaderReaderIOResult. This is the curried version that returns an operator.
func Let ¶
func Let[R, S1, S2, T any]( setter func(T) func(S1) S2, f func(S1) T, ) Operator[R, S1, S2]
Let attaches a pure computation result to a context [S1] to produce a context [S2]. Unlike Bind, the computation function f is pure (doesn't perform effects).
Example:
readerreaderioeither.Let(
func(fullName string) func(State) State {
return func(s State) State { s.FullName = fullName; return s }
},
func(s State) string {
return s.FirstName + " " + s.LastName
},
)
func LetL ¶
func LetL[R, S, T any]( lens Lens[S, T], f func(T) T, ) Operator[R, S, S]
LetL is a lens-based version of Let that uses a lens to focus on a specific field in the context.
func LetTo ¶
func LetTo[R, S1, S2, T any]( setter func(T) func(S1) S2, b T, ) Operator[R, S1, S2]
LetTo attaches a constant value to a context [S1] to produce a context [S2].
Example:
readerreaderioeither.LetTo(
func(status string) func(State) State {
return func(s State) State { s.Status = status; return s }
},
"active",
)
func LetToL ¶
func LetToL[R, S, T any]( lens Lens[S, T], b T, ) Operator[R, S, S]
LetToL is a lens-based version of LetTo that uses a lens to focus on a specific field in the context.
func Map ¶
func Map[R, A, B any](f func(A) B) Operator[R, A, B]
Map applies a function to the value inside a ReaderReaderIOResult (Functor operation). This is the curried version that returns an operator.
func MapLeft ¶
MapLeft transforms the error value if the computation fails. Has no effect if the computation succeeds. This is the curried version that returns an operator.
func MapTo ¶
func MapTo[R, A, B any](b B) Operator[R, A, B]
MapTo replaces the value inside a ReaderReaderIOResult with a constant value. This is the curried version that returns an operator.
func Tap ¶
func Tap[R, A, B any](f Kleisli[R, A, B]) Operator[R, A, A]
Tap is an alias for ChainFirst. Executes a side effect while preserving the original value.
func TapEitherK ¶
TapEitherK is an alias for ChainFirstEitherK. Executes an Either-returning side effect while preserving the original value.
func TapIOK ¶
TapIOK is an alias for ChainFirstIOK. Executes an IO-returning side effect while preserving the original value.
func TapReaderEitherK ¶
TapReaderEitherK is an alias for ChainFirstReaderEitherK. Executes a ReaderEither-returning side effect while preserving the original value.
func TapReaderIOK ¶
TapReaderIOK is an alias for ChainFirstReaderIOK. Executes a ReaderIO-returning side effect while preserving the original value.
func TapReaderK ¶
TapReaderK is an alias for ChainFirstReaderK. Executes a Reader-returning side effect while preserving the original value.
type Option ¶
Option represents an optional value that may or may not be present. It's an alias for option.Option[A].
type Predicate ¶
Predicate represents a function that tests whether a value of type A satisfies some condition. It's an alias for predicate.Predicate[A].
type Reader ¶
Reader represents a computation that depends on an environment of type R and produces a value of type A. It's an alias for reader.Reader[R, A].
type ReaderIO ¶
ReaderIO represents a computation that depends on an environment of type R and performs side effects to produce a value of type A. It's an alias for readerio.ReaderIO[R, A].
type ReaderIOResult ¶
type ReaderIOResult[R, A any] = readerioresult.ReaderIOResult[R, A]
ReaderIOResult represents a computation that depends on an environment of type R, performs side effects, and may fail with an error. It's an alias for readerioresult.ReaderIOResult[R, A].
type ReaderOption ¶
type ReaderOption[R, A any] = readeroption.ReaderOption[R, A]
ReaderOption represents a computation that depends on an environment of type R and produces an optional value of type A. It's an alias for readeroption.ReaderOption[R, A].
type ReaderReaderIOEither ¶
type ReaderReaderIOEither[R, C, E, A any] = readerreaderioeither.ReaderReaderIOEither[R, C, E, A]
ReaderReaderIOEither is the base monad transformer that combines: - Reader[R, ...] for outer dependency injection - Reader[C, ...] for inner dependency injection (typically context.Context) - IO for side effects - Either[E, A] for error handling It's an alias for readerreaderioeither.ReaderReaderIOEither[R, C, E, A].
type ReaderReaderIOResult ¶
type ReaderReaderIOResult[R, A any] = ReaderReaderIOEither[R, context.Context, error, A]
ReaderReaderIOResult is the main type of this package, specializing ReaderReaderIOEither with context.Context as the inner reader type and error as the error type.
Type structure:
ReaderReaderIOResult[R, A] = R -> context.Context -> IO[Either[error, A]]
This represents a computation that: 1. Depends on an outer environment of type R (e.g., application config) 2. Depends on a context.Context for cancellation and request-scoped values 3. Performs side effects (IO) 4. May fail with an error or succeed with a value of type A
This is the primary type used throughout the package for composing context-aware, effectful computations with error handling.
func Ask ¶
func Ask[R any]() ReaderReaderIOResult[R, R]
Ask retrieves the outer environment R. Returns a ReaderReaderIOResult that succeeds with the environment value.
func Asks ¶
func Asks[R, A any](r Reader[R, A]) ReaderReaderIOResult[R, A]
Asks retrieves a value derived from the outer environment R using the provided function.
func Bracket ¶
func Bracket[ R, A, B, ANY any]( acquire ReaderReaderIOResult[R, A], use Kleisli[R, A, B], release func(A, Result[B]) ReaderReaderIOResult[R, ANY], ) ReaderReaderIOResult[R, B]
Bracket ensures that a resource is properly cleaned up regardless of whether the operation succeeds or fails. It follows the acquire-use-release pattern with access to both outer (R) and inner (C) reader contexts.
The release action is always called after the use action completes, whether it succeeds or fails. This makes it ideal for managing resources like file handles, database connections, or locks.
Parameters:
- acquire: Acquires the resource, returning a ReaderReaderIOEither[R, C, E, A]
- use: Uses the acquired resource to perform an operation, returning ReaderReaderIOEither[R, C, E, B]
- release: Releases the resource, receiving both the resource and the result of use
Returns:
- A ReaderReaderIOEither[R, C, E, B] that safely manages the resource lifecycle
The release function receives:
- The acquired resource (A)
- The result of the use function (Either[E, B])
Example:
type OuterConfig struct {
ConnectionPool string
}
type InnerConfig struct {
Timeout time.Duration
}
// Acquire a database connection
acquire := func(outer OuterConfig) readerioeither.ReaderIOEither[InnerConfig, error, *sql.DB] {
return func(inner InnerConfig) ioeither.IOEither[error, *sql.DB] {
return ioeither.TryCatch(
func() (*sql.DB, error) {
return sql.Open("postgres", outer.ConnectionPool)
},
func(err error) error { return err },
)
}
}
// Use the connection
use := func(db *sql.DB) readerreaderioeither.ReaderReaderIOEither[OuterConfig, InnerConfig, error, []User] {
return func(outer OuterConfig) readerioeither.ReaderIOEither[InnerConfig, error, []User] {
return func(inner InnerConfig) ioeither.IOEither[error, []User] {
return queryUsers(db, inner.Timeout)
}
}
}
// Release the connection
release := func(db *sql.DB, result either.Either[error, []User]) readerreaderioeither.ReaderReaderIOEither[OuterConfig, InnerConfig, error, any] {
return func(outer OuterConfig) readerioeither.ReaderIOEither[InnerConfig, error, any] {
return func(inner InnerConfig) ioeither.IOEither[error, any] {
return ioeither.TryCatch(
func() (any, error) {
return nil, db.Close()
},
func(err error) error { return err },
)
}
}
}
result := readerreaderioeither.Bracket(acquire, use, release)
func Do ¶
func Do[R, S any]( empty S, ) ReaderReaderIOResult[R, S]
Do creates an empty context of type [S] to be used with the Bind operation. This is the starting point for do-notation style composition with two reader contexts.
Example:
type State struct {
User User
Posts []Post
}
type OuterEnv struct {
Database string
}
type InnerEnv struct {
UserRepo UserRepository
PostRepo PostRepository
}
result := readerreaderioeither.Do[OuterEnv, InnerEnv, error](State{})
func Flatten ¶
func Flatten[R, A any](mma ReaderReaderIOResult[R, ReaderReaderIOResult[R, A]]) ReaderReaderIOResult[R, A]
Flatten removes one level of nesting from a nested ReaderReaderIOResult. Converts ReaderReaderIOResult[R, ReaderReaderIOResult[R, A]] to ReaderReaderIOResult[R, A].
func FromEither ¶
FromEither lifts an Either into a ReaderReaderIOResult.
func FromIO ¶
func FromIO[R, A any](ma IO[A]) ReaderReaderIOResult[R, A]
FromIO lifts an IO into a ReaderReaderIOResult. The IO's result is wrapped in a Right (success) value.
func FromIOEither ¶
FromIOEither lifts an IOEither into a ReaderReaderIOResult.
func FromIOResult ¶
func FromIOResult[R, A any](ma IOResult[A]) ReaderReaderIOResult[R, A]
FromIOResult lifts an IOResult into a ReaderReaderIOResult. Alias for FromIOEither since IOResult is IOEither[error, A].
func FromReader ¶
func FromReader[R, A any](ma Reader[R, A]) ReaderReaderIOResult[R, A]
FromReader lifts a Reader into a ReaderReaderIOResult. The Reader's result is wrapped in a Right (success) value.
func FromReaderEither ¶
func FromReaderEither[R, A any](ma RE.ReaderEither[R, error, A]) ReaderReaderIOResult[R, A]
FromReaderEither lifts a ReaderEither into a ReaderReaderIOResult.
func FromReaderIO ¶
func FromReaderIO[R, A any](ma ReaderIO[R, A]) ReaderReaderIOResult[R, A]
FromReaderIO lifts a ReaderIO into a ReaderReaderIOResult. The IO computation is wrapped in a Right (success) value.
func FromReaderIOResult ¶
func FromReaderIOResult[R, A any](ma ReaderIOResult[R, A]) ReaderReaderIOResult[R, A]
FromReaderIOResult lifts a ReaderIOResult into a ReaderReaderIOResult. This adds an additional reader layer to the computation.
func FromResult ¶
func FromResult[R, A any](t Result[A]) ReaderReaderIOResult[R, A]
FromResult lifts a Result into a ReaderReaderIOResult. Alias for FromEither since Result is Either[error, A].
func Left ¶
Left creates a ReaderReaderIOResult that fails with the given error. This is the failure constructor for the Result type.
func LeftIO ¶
LeftIO lifts an IO that produces an error into a ReaderReaderIOResult as a Left (failure) value.
func LeftReader ¶
LeftReader lifts a Reader that produces an error into a ReaderReaderIOResult as a Left (failure) value.
func LeftReaderIO ¶
LeftReaderIO lifts a ReaderIO that produces an error into a ReaderReaderIOResult as a Left (failure) value.
func MonadAlt ¶
func MonadAlt[R, A any](first ReaderReaderIOResult[R, A], second Lazy[ReaderReaderIOResult[R, A]]) ReaderReaderIOResult[R, A]
MonadAlt provides alternative/fallback behavior. If the first computation fails, it tries the second (lazy-evaluated). This is the monadic version that takes both computations as parameters.
func MonadAp ¶
func MonadAp[R, A, B any](fab ReaderReaderIOResult[R, func(A) B], fa ReaderReaderIOResult[R, A]) ReaderReaderIOResult[R, B]
MonadAp applies a function wrapped in a ReaderReaderIOResult to a value wrapped in a ReaderReaderIOResult (Applicative operation). This is the monadic version that takes both computations as parameters.
func MonadApPar ¶
func MonadApPar[R, A, B any](fab ReaderReaderIOResult[R, func(A) B], fa ReaderReaderIOResult[R, A]) ReaderReaderIOResult[R, B]
MonadApPar is like MonadAp but evaluates effects in parallel.
func MonadApSeq ¶
func MonadApSeq[R, A, B any](fab ReaderReaderIOResult[R, func(A) B], fa ReaderReaderIOResult[R, A]) ReaderReaderIOResult[R, B]
MonadApSeq is like MonadAp but evaluates effects sequentially.
func MonadChain ¶
func MonadChain[R, A, B any](fa ReaderReaderIOResult[R, A], f Kleisli[R, A, B]) ReaderReaderIOResult[R, B]
MonadChain sequences two computations, where the second depends on the result of the first (Monad operation). This is the monadic version that takes the computation as the first parameter.
func MonadChainEitherK ¶
func MonadChainEitherK[R, A, B any](ma ReaderReaderIOResult[R, A], f either.Kleisli[error, A, B]) ReaderReaderIOResult[R, B]
MonadChainEitherK chains a computation that returns an Either. The Either is automatically lifted into ReaderReaderIOResult. This is the monadic version that takes the computation as the first parameter.
func MonadChainFirst ¶
func MonadChainFirst[R, A, B any](fa ReaderReaderIOResult[R, A], f Kleisli[R, A, B]) ReaderReaderIOResult[R, A]
MonadChainFirst sequences two computations but returns the result of the first. Useful for performing side effects while preserving the original value. This is the monadic version that takes the computation as the first parameter.
func MonadChainFirstEitherK ¶
func MonadChainFirstEitherK[R, A, B any](ma ReaderReaderIOResult[R, A], f either.Kleisli[error, A, B]) ReaderReaderIOResult[R, A]
MonadChainFirstEitherK chains a computation that returns an Either but preserves the original value. Useful for validation or side effects that may fail. This is the monadic version that takes the computation as the first parameter.
func MonadChainFirstIOK ¶
func MonadChainFirstIOK[R, A, B any](ma ReaderReaderIOResult[R, A], f io.Kleisli[A, B]) ReaderReaderIOResult[R, A]
MonadChainFirstIOK chains a computation that returns an IO but preserves the original value. This is the monadic version that takes the computation as the first parameter.
func MonadChainFirstReaderEitherK ¶
func MonadChainFirstReaderEitherK[R, A, B any](ma ReaderReaderIOResult[R, A], f RE.Kleisli[R, error, A, B]) ReaderReaderIOResult[R, A]
MonadChainFirstReaderEitherK chains a computation that returns a ReaderEither but preserves the original value. This is the monadic version that takes the computation as the first parameter.
func MonadChainFirstReaderIOK ¶
func MonadChainFirstReaderIOK[R, A, B any](ma ReaderReaderIOResult[R, A], f readerio.Kleisli[R, A, B]) ReaderReaderIOResult[R, A]
MonadChainFirstReaderIOK chains a computation that returns a ReaderIO but preserves the original value. This is the monadic version that takes the computation as the first parameter.
func MonadChainFirstReaderK ¶
func MonadChainFirstReaderK[R, A, B any](ma ReaderReaderIOResult[R, A], f reader.Kleisli[R, A, B]) ReaderReaderIOResult[R, A]
MonadChainFirstReaderK chains a computation that returns a Reader but preserves the original value. This is the monadic version that takes the computation as the first parameter.
func MonadChainIOEitherK ¶
func MonadChainIOEitherK[R, A, B any](ma ReaderReaderIOResult[R, A], f IOE.Kleisli[error, A, B]) ReaderReaderIOResult[R, B]
MonadChainIOEitherK chains a computation that returns an IOEither. The IOEither is automatically lifted into ReaderReaderIOResult. This is the monadic version that takes the computation as the first parameter.
func MonadChainIOK ¶
func MonadChainIOK[R, A, B any](ma ReaderReaderIOResult[R, A], f io.Kleisli[A, B]) ReaderReaderIOResult[R, B]
MonadChainIOK chains a computation that returns an IO. The IO is automatically lifted into ReaderReaderIOResult. This is the monadic version that takes the computation as the first parameter.
func MonadChainLeft ¶
func MonadChainLeft[R, A any](fa ReaderReaderIOResult[R, A], f Kleisli[R, error, A]) ReaderReaderIOResult[R, A]
MonadChainLeft handles errors by chaining a recovery computation. If the computation fails, the error is passed to f for recovery. This is the monadic version that takes the computation as the first parameter.
func MonadChainReaderEitherK ¶
func MonadChainReaderEitherK[R, A, B any](ma ReaderReaderIOResult[R, A], f RE.Kleisli[R, error, A, B]) ReaderReaderIOResult[R, B]
MonadChainReaderEitherK chains a computation that returns a ReaderEither. The ReaderEither is automatically lifted into ReaderReaderIOResult. This is the monadic version that takes the computation as the first parameter.
func MonadChainReaderIOK ¶
func MonadChainReaderIOK[R, A, B any](ma ReaderReaderIOResult[R, A], f readerio.Kleisli[R, A, B]) ReaderReaderIOResult[R, B]
MonadChainReaderIOK chains a computation that returns a ReaderIO. The ReaderIO is automatically lifted into ReaderReaderIOResult. This is the monadic version that takes the computation as the first parameter.
func MonadChainReaderK ¶
func MonadChainReaderK[R, A, B any](ma ReaderReaderIOResult[R, A], f reader.Kleisli[R, A, B]) ReaderReaderIOResult[R, B]
MonadChainReaderK chains a computation that returns a Reader. The Reader is automatically lifted into ReaderReaderIOResult. This is the monadic version that takes the computation as the first parameter.
func MonadFlap ¶
func MonadFlap[R, B, A any](fab ReaderReaderIOResult[R, func(A) B], a A) ReaderReaderIOResult[R, B]
MonadFlap applies a value to a function wrapped in a ReaderReaderIOResult. This is the monadic version that takes the computation as the first parameter.
func MonadMap ¶
func MonadMap[R, A, B any](fa ReaderReaderIOResult[R, A], f func(A) B) ReaderReaderIOResult[R, B]
MonadMap applies a function to the value inside a ReaderReaderIOResult (Functor operation). This is the monadic version that takes the computation as the first parameter.
func MonadMapLeft ¶
func MonadMapLeft[R, A any](fa ReaderReaderIOResult[R, A], f Endmorphism[error]) ReaderReaderIOResult[R, A]
MonadMapLeft transforms the error value if the computation fails. Has no effect if the computation succeeds. This is the monadic version that takes the computation as the first parameter.
func MonadMapTo ¶
func MonadMapTo[R, A, B any](fa ReaderReaderIOResult[R, A], b B) ReaderReaderIOResult[R, B]
MonadMapTo replaces the value inside a ReaderReaderIOResult with a constant value. This is the monadic version that takes the computation as the first parameter.
func MonadTap ¶
func MonadTap[R, A, B any](fa ReaderReaderIOResult[R, A], f Kleisli[R, A, B]) ReaderReaderIOResult[R, A]
MonadTap is an alias for MonadChainFirst. Executes a side effect while preserving the original value.
func MonadTapEitherK ¶
func MonadTapEitherK[R, A, B any](ma ReaderReaderIOResult[R, A], f either.Kleisli[error, A, B]) ReaderReaderIOResult[R, A]
MonadTapEitherK is an alias for MonadChainFirstEitherK. Executes an Either-returning side effect while preserving the original value.
func MonadTapIOK ¶
func MonadTapIOK[R, A, B any](ma ReaderReaderIOResult[R, A], f io.Kleisli[A, B]) ReaderReaderIOResult[R, A]
MonadTapIOK is an alias for MonadChainFirstIOK. Executes an IO-returning side effect while preserving the original value.
func MonadTapReaderEitherK ¶
func MonadTapReaderEitherK[R, A, B any](ma ReaderReaderIOResult[R, A], f RE.Kleisli[R, error, A, B]) ReaderReaderIOResult[R, A]
MonadTapReaderEitherK is an alias for MonadChainFirstReaderEitherK. Executes a ReaderEither-returning side effect while preserving the original value.
func MonadTapReaderIOK ¶
func MonadTapReaderIOK[R, A, B any](ma ReaderReaderIOResult[R, A], f readerio.Kleisli[R, A, B]) ReaderReaderIOResult[R, A]
MonadTapReaderIOK is an alias for MonadChainFirstReaderIOK. Executes a ReaderIO-returning side effect while preserving the original value.
func MonadTapReaderK ¶
func MonadTapReaderK[R, A, B any](ma ReaderReaderIOResult[R, A], f reader.Kleisli[R, A, B]) ReaderReaderIOResult[R, A]
MonadTapReaderK is an alias for MonadChainFirstReaderK. Executes a Reader-returning side effect while preserving the original value.
func Of ¶
func Of[R, A any](a A) ReaderReaderIOResult[R, A]
Of creates a ReaderReaderIOResult that succeeds with the given value (Pointed operation). Alias for Right.
func Retrying ¶
func Retrying[R, A any]( policy retry.RetryPolicy, action Kleisli[R, retry.RetryStatus, A], check Predicate[Result[A]], ) ReaderReaderIOResult[R, A]
Retrying executes an action with automatic retry logic based on a retry policy. It retries the action when it fails or when the check predicate returns false.
This function is useful for handling transient failures in operations like:
- Network requests that may temporarily fail
- Database operations that may encounter locks
- External service calls that may be temporarily unavailable
Parameters:
- policy: Defines the retry behavior (number of retries, delays, backoff strategy)
- action: The computation to retry, receives retry status information
- check: Predicate to determine if the result should trigger a retry (returns true to continue, false to retry)
The action receives a retry.RetryStatus that contains:
- IterNumber: Current iteration number (0-based)
- CumulativeDelay: Total delay accumulated so far
- PreviousDelay: Delay from the previous iteration
Returns:
- A ReaderReaderIOResult that executes the action with retry logic
Example:
import (
"errors"
"time"
"github.com/IBM/fp-go/v2/retry"
)
type Config struct {
MaxRetries int
BaseDelay time.Duration
}
// Create a retry policy with exponential backoff
policy := retry.ExponentialBackoff(100*time.Millisecond, 5*time.Second)
policy = retry.LimitRetries(3, policy)
// Action that may fail transiently
action := func(status retry.RetryStatus) ReaderReaderIOResult[Config, string] {
return func(cfg Config) ReaderIOResult[context.Context, string] {
return func(ctx context.Context) IOResult[string] {
return func() Either[error, string] {
// Simulate transient failure
if status.IterNumber < 2 {
return either.Left[string](errors.New("transient error"))
}
return either.Right[error]("success")
}
}
}
}
// Check if we should retry (retry on any error)
check := func(result Result[string]) bool {
return either.IsRight(result) // Continue only if successful
}
// Execute with retry logic
result := Retrying(policy, action, check)
func Right ¶
func Right[R, A any](a A) ReaderReaderIOResult[R, A]
Right creates a ReaderReaderIOResult that succeeds with the given value. This is the success constructor for the Result type.
func RightIO ¶
func RightIO[R, A any](ma IO[A]) ReaderReaderIOResult[R, A]
RightIO lifts an IO into a ReaderReaderIOResult as a Right (success) value.
func RightReader ¶
func RightReader[R, A any](ma Reader[R, A]) ReaderReaderIOResult[R, A]
RightReader lifts a Reader into a ReaderReaderIOResult as a Right (success) value.
func RightReaderIO ¶
func RightReaderIO[R, A any](ma ReaderIO[R, A]) ReaderReaderIOResult[R, A]
RightReaderIO lifts a ReaderIO into a ReaderReaderIOResult as a Right (success) value. Alias for FromReaderIO.
type Result ¶
Result is a specialized Either with error as the left type. It's an alias for result.Result[A] which is Either[error, A].
type Trampoline ¶
type Trampoline[L, B any] = tailrec.Trampoline[L, B]
Trampoline is used for stack-safe recursion through tail call optimization. It's an alias for tailrec.Trampoline[L, B].