Documentation
¶
Overview ¶
Package effect provides a functional effect system for managing side effects in Go.
Overview ¶
The effect package is a high-level abstraction for composing effectful computations that may fail, require dependencies (context), and perform I/O operations. It is built on top of ReaderReaderIOResult, providing a clean API for dependency injection and error handling.
Naming Conventions ¶
The naming conventions in this package are modeled after effect-ts (https://effect.website/), a popular TypeScript library for functional effect systems. This alignment helps developers familiar with effect-ts to quickly understand and use this Go implementation.
Core Type ¶
The central type is Effect[C, A], which represents:
- C: The context/dependency type required by the effect
- A: The success value type produced by the effect
An Effect can:
- Succeed with a value of type A
- Fail with an error
- Require a context of type C
- Perform I/O operations
Basic Operations ¶
Creating Effects:
// Create a successful effect
effect.Succeed[MyContext, string]("hello")
// Create a failed effect
effect.Fail[MyContext, string](errors.New("failed"))
// Lift a pure value into an effect
effect.Of[MyContext, int](42)
Transforming Effects:
// Map over the success value
effect.Map[MyContext](func(x int) string {
return strconv.Itoa(x)
})
// Chain effects together (flatMap)
effect.Chain[MyContext](func(x int) Effect[MyContext, string] {
return effect.Succeed[MyContext, string](strconv.Itoa(x))
})
// Tap into an effect without changing its value
effect.Tap[MyContext](func(x int) Effect[MyContext, any] {
return effect.Succeed[MyContext, any](fmt.Println(x))
})
Dependency Injection ¶
Effects can access their required context:
// Transform the context before passing it to an effect
effect.Local[OuterCtx, InnerCtx](func(outer OuterCtx) InnerCtx {
return outer.Inner
})
// Provide a context to run an effect
effect.Provide[MyContext, string](myContext)
Do Notation ¶
The package provides "do notation" for composing effects in a sequential, imperative style:
type State struct {
X int
Y string
}
result := effect.Do[MyContext](State{}).
Bind(func(y string) func(State) State {
return func(s State) State {
s.Y = y
return s
}
}, fetchString).
Let(func(x int) func(State) State {
return func(s State) State {
s.X = x
return s
}
}, func(s State) int {
return len(s.Y)
})
Bind Operations ¶
The package provides various bind operations for integrating with other effect types:
- BindIOK: Bind an IO operation
- BindIOEitherK: Bind an IOEither operation
- BindIOResultK: Bind an IOResult operation
- BindReaderK: Bind a Reader operation
- BindReaderIOK: Bind a ReaderIO operation
- BindEitherK: Bind an Either operation
Each bind operation has a corresponding "L" variant for working with lenses:
- BindL, BindIOKL, BindReaderKL, etc.
Applicative Operations ¶
Apply effects in parallel:
// Apply a function effect to a value effect effect.Ap[string, MyContext](valueEffect)(functionEffect) // Apply effects to build up a structure effect.ApS[MyContext](setter, effect1)
Traversal ¶
Traverse collections with effects:
// Map an array with an effectful function
effect.TraverseArray[MyContext](func(x int) Effect[MyContext, string] {
return effect.Succeed[MyContext, string](strconv.Itoa(x))
})
Retry Logic ¶
Retry effects with configurable policies:
effect.Retrying[MyContext, string](
retryPolicy,
func(status retry.RetryStatus) Effect[MyContext, string] {
return fetchData()
},
func(result Result[string]) bool {
return result.IsLeft() // retry on error
},
)
Monoids ¶
Combine effects using monoid operations:
// Combine effects using applicative semantics effect.ApplicativeMonoid[MyContext](stringMonoid) // Combine effects using alternative semantics (first success) effect.AlternativeMonoid[MyContext](stringMonoid)
Running Effects ¶
To execute an effect:
// Provide the context ioResult := effect.Provide[MyContext, string](myContext)(myEffect) // Run synchronously readerResult := effect.RunSync(ioResult) // Execute with a context.Context value, err := readerResult(ctx)
Integration with Other Packages ¶
The effect package integrates seamlessly with other fp-go packages:
- either: For error handling
- io: For I/O operations
- reader: For dependency injection
- result: For result types
- retry: For retry logic
- monoid: For combining effects
Example ¶
type Config struct {
APIKey string
BaseURL string
}
func fetchUser(id int) Effect[Config, User] {
return effect.Chain[Config](func(cfg Config) Effect[Config, User] {
// Use cfg.APIKey and cfg.BaseURL
return effect.Succeed[Config, User](User{ID: id})
})(effect.Of[Config, Config](Config{}))
}
func main() {
cfg := Config{APIKey: "key", BaseURL: "https://api.example.com"}
userEffect := fetchUser(42)
// Run the effect
ioResult := effect.Provide(cfg)(userEffect)
readerResult := effect.RunSync(ioResult)
user, err := readerResult(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Printf("User: %+v\n", user)
}
Index ¶
- func LocalEffectK[A, C1, C2 any](f Kleisli[C2, C2, C1]) func(Effect[C1, A]) Effect[C2, A]
- func LocalIOK[A, C1, C2 any](f io.Kleisli[C2, C1]) func(Effect[C1, A]) Effect[C2, A]
- func LocalIOResultK[A, C1, C2 any](f ioresult.Kleisli[C2, C1]) func(Effect[C1, A]) Effect[C2, A]
- func LocalResultK[A, C1, C2 any](f result.Kleisli[C2, C1]) func(Effect[C1, A]) Effect[C2, A]
- func LocalThunkK[A, C1, C2 any](f thunk.Kleisli[C2, C1]) func(Effect[C1, A]) Effect[C2, A]
- func Provide[A, C any](c C) func(Effect[C, A]) ReaderIOResult[A]
- func Read[A, C any](c C) func(Effect[C, A]) Thunk[A]
- func RunSync[A any](fa ReaderIOResult[A]) readerresult.ReaderResult[A]
- type Effect
- func Do[C, S any](empty S) Effect[C, S]
- func Fail[C, A any](err error) Effect[C, A]
- func FromThunk[C, A any](f Thunk[A]) Effect[C, A]
- func Of[C, A any](a A) Effect[C, A]
- func Retrying[C, A any](policy retry.RetryPolicy, action Kleisli[C, retry.RetryStatus, A], ...) Effect[C, A]
- func Succeed[C, A any](a A) Effect[C, A]
- func Suspend[C, A any](fa Lazy[Effect[C, A]]) Effect[C, A]
- type Either
- type IO
- type IOEither
- type IOResult
- type Kleisli
- func Contramap[A, C1, C2 any](acc Reader[C1, C2]) Kleisli[C1, Effect[C2, A], A]
- func Local[A, C1, C2 any](acc Reader[C1, C2]) Kleisli[C1, Effect[C2, A], A]
- func Ternary[C, A, B any](pred Predicate[A], onTrue, onFalse Kleisli[C, A, B]) Kleisli[C, A, B]
- func TraverseArray[C, A, B any](f Kleisli[C, A, B]) Kleisli[C, []A, []B]
- type Lazy
- type Lens
- type Monoid
- type Operator
- func Ap[B, C, A any](fa Effect[C, A]) Operator[C, func(A) B, B]
- func ApEitherS[C, S1, S2, T any](setter func(T) func(S1) S2, fa Either[error, T]) Operator[C, S1, S2]
- func ApEitherSL[C, S, T any](lens Lens[S, T], fa Either[error, T]) Operator[C, S, S]
- func ApIOEitherS[C, S1, S2, T any](setter func(T) func(S1) S2, fa IOEither[error, T]) Operator[C, S1, S2]
- func ApIOEitherSL[C, S, T any](lens Lens[S, T], fa IOEither[error, T]) Operator[C, S, S]
- func ApIOS[C, S1, S2, T any](setter func(T) func(S1) S2, fa IO[T]) Operator[C, S1, S2]
- func ApIOSL[C, S, T any](lens Lens[S, T], fa IO[T]) Operator[C, S, S]
- func ApReaderIOS[C, S1, S2, T any](setter func(T) func(S1) S2, fa ReaderIO[C, T]) Operator[C, S1, S2]
- func ApReaderIOSL[C, S, T any](lens Lens[S, T], fa ReaderIO[C, T]) Operator[C, S, S]
- func ApReaderS[C, S1, S2, T any](setter func(T) func(S1) S2, fa Reader[C, T]) Operator[C, S1, S2]
- func ApReaderSL[C, S, T any](lens Lens[S, T], fa Reader[C, T]) Operator[C, S, S]
- func ApS[C, S1, S2, T any](setter func(T) func(S1) S2, fa Effect[C, T]) Operator[C, S1, S2]
- func ApSL[C, S, T any](lens Lens[S, T], fa Effect[C, T]) Operator[C, S, S]
- func Bind[C, S1, S2, T any](setter func(T) func(S1) S2, f Kleisli[C, S1, T]) Operator[C, S1, S2]
- func BindEitherK[C, S1, S2, T any](setter func(T) func(S1) S2, f either.Kleisli[error, S1, T]) Operator[C, S1, S2]
- func BindIOEitherK[C, S1, S2, T any](setter func(T) func(S1) S2, f ioeither.Kleisli[error, S1, T]) Operator[C, S1, S2]
- func BindIOEitherKL[C, S, T any](lens Lens[S, T], f ioeither.Kleisli[error, T, T]) Operator[C, S, S]
- func BindIOK[C, S1, S2, T any](setter func(T) func(S1) S2, f io.Kleisli[S1, T]) Operator[C, S1, S2]
- func BindIOKL[C, S, T any](lens Lens[S, T], f io.Kleisli[T, T]) Operator[C, S, S]
- func BindIOResultK[C, S1, S2, T any](setter func(T) func(S1) S2, f ioresult.Kleisli[S1, T]) Operator[C, S1, S2]
- func BindL[C, S, T any](lens Lens[S, T], f func(T) Effect[C, T]) Operator[C, S, S]
- func BindReaderIOK[C, S1, S2, T any](setter func(T) func(S1) S2, f readerio.Kleisli[C, S1, T]) Operator[C, S1, S2]
- func BindReaderIOKL[C, S, T any](lens Lens[S, T], f readerio.Kleisli[C, T, T]) Operator[C, S, S]
- func BindReaderK[C, S1, S2, T any](setter func(T) func(S1) S2, f reader.Kleisli[C, S1, T]) Operator[C, S1, S2]
- func BindReaderKL[C, S, T any](lens Lens[S, T], f reader.Kleisli[C, T, T]) Operator[C, S, S]
- func BindTo[C, S1, T any](setter func(T) S1) Operator[C, T, S1]
- func Chain[C, A, B any](f Kleisli[C, A, B]) Operator[C, A, B]
- func ChainFirstIOK[C, A, B any](f io.Kleisli[A, B]) Operator[C, A, A]
- func ChainIOK[C, A, B any](f io.Kleisli[A, B]) Operator[C, A, B]
- func ChainReaderIOK[C, A, B any](f readerio.Kleisli[C, A, B]) Operator[C, A, B]
- func ChainReaderK[C, A, B any](f reader.Kleisli[C, A, B]) Operator[C, A, B]
- func ChainResultK[C, A, B any](f result.Kleisli[A, B]) Operator[C, A, B]
- func ChainThunkK[C, A, B any](f thunk.Kleisli[A, B]) Operator[C, A, B]
- func Let[C, S1, S2, T any](setter func(T) func(S1) S2, f func(S1) T) Operator[C, S1, S2]
- func LetL[C, S, T any](lens Lens[S, T], f func(T) T) Operator[C, S, S]
- func LetTo[C, S1, S2, T any](setter func(T) func(S1) S2, b T) Operator[C, S1, S2]
- func LetToL[C, S, T any](lens Lens[S, T], b T) Operator[C, S, S]
- func Map[C, A, B any](f func(A) B) Operator[C, A, B]
- func Tap[C, A, ANY any](f Kleisli[C, A, ANY]) Operator[C, A, A]
- func TapIOK[C, A, B any](f io.Kleisli[A, B]) Operator[C, A, A]
- type Predicate
- type Reader
- type ReaderIO
- type ReaderIOResult
- type Result
- type Thunk
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func LocalEffectK ¶
func LocalEffectK[A, C1, C2 any](f Kleisli[C2, C2, C1]) func(Effect[C1, A]) Effect[C2, A]
LocalEffectK transforms the context of an Effect using an Effect-returning function. This is the most powerful context transformation function, allowing the transformation itself to be effectful (can fail, perform I/O, and access the outer context).
LocalEffectK takes a Kleisli arrow that:
- Accepts the outer context C2
- Returns an Effect that produces the inner context C1
- Can fail with an error during context transformation
- Can perform I/O operations during transformation
This is useful when:
- Context transformation requires I/O (e.g., loading config from a file)
- Context transformation can fail (e.g., validating or parsing context)
- Context transformation needs to access the outer context
Type Parameters:
- A: The value type produced by the effect
- C1: The inner context type (required by the original effect)
- C2: The outer context type (provided to the transformed effect)
Parameters:
- f: A Kleisli arrow (C2 -> Effect[C2, C1]) that transforms C2 to C1 effectfully
Returns:
- A function that transforms Effect[C1, A] to Effect[C2, A]
Example:
type DatabaseConfig struct {
ConnectionString string
}
type AppConfig struct {
ConfigPath string
}
// Effect that needs DatabaseConfig
dbEffect := effect.Of[DatabaseConfig, string]("query result")
// Transform AppConfig to DatabaseConfig effectfully
// (e.g., load config from file, which can fail)
loadConfig := func(app AppConfig) Effect[AppConfig, DatabaseConfig] {
return effect.Chain[AppConfig](func(_ AppConfig) Effect[AppConfig, DatabaseConfig] {
// Simulate loading config from file (can fail)
return effect.Of[AppConfig, DatabaseConfig](DatabaseConfig{
ConnectionString: "loaded from " + app.ConfigPath,
})
})(effect.Of[AppConfig, AppConfig](app))
}
// Apply the transformation
transform := effect.LocalEffectK[string, DatabaseConfig, AppConfig](loadConfig)
appEffect := transform(dbEffect)
// Run with AppConfig
ioResult := effect.Provide(AppConfig{ConfigPath: "/etc/app.conf"})(appEffect)
readerResult := effect.RunSync(ioResult)
result, err := readerResult(context.Background())
Comparison with other Local functions:
- Local/Contramap: Pure context transformation (C2 -> C1)
- LocalIOK: IO-based transformation (C2 -> IO[C1])
- LocalIOResultK: IO with error handling (C2 -> IOResult[C1])
- LocalReaderIOResultK: Reader-based with IO and errors (C2 -> ReaderIOResult[C1])
- LocalEffectK: Full Effect transformation (C2 -> Effect[C2, C1])
func LocalIOK ¶
LocalIOK transforms the context using an IO-based function. This allows the context transformation itself to perform I/O operations.
Type Parameters ¶
- A: The value type produced by the effect
- C1: The inner context type (what the effect needs)
- C2: The outer context type (what you have)
Parameters ¶
- f: An IO function that transforms C2 to C1
Returns ¶
- func(Effect[C1, A]) Effect[C2, A]: A function that adapts the effect
Example ¶
loadConfig := func(path string) io.IO[Config] {
return func() Config { /* load from file */ }
}
transform := effect.LocalIOK[string](loadConfig)
adapted := transform(configEffect)
func LocalIOResultK ¶
LocalIOResultK transforms the context using an IOResult-based function. This allows the context transformation to perform I/O and handle errors.
Type Parameters ¶
- A: The value type produced by the effect
- C1: The inner context type (what the effect needs)
- C2: The outer context type (what you have)
Parameters ¶
- f: An IOResult function that transforms C2 to C1
Returns ¶
- func(Effect[C1, A]) Effect[C2, A]: A function that adapts the effect
Example ¶
loadConfig := func(path string) ioresult.IOResult[Config] {
return func() result.Result[Config] {
// load from file, may fail
}
}
transform := effect.LocalIOResultK[string](loadConfig)
adapted := transform(configEffect)
func LocalResultK ¶
LocalResultK transforms the context using a Result-based function. This allows the context transformation to fail with an error.
Type Parameters ¶
- A: The value type produced by the effect
- C1: The inner context type (what the effect needs)
- C2: The outer context type (what you have)
Parameters ¶
- f: A Result function that transforms C2 to C1
Returns ¶
- func(Effect[C1, A]) Effect[C2, A]: A function that adapts the effect
Example ¶
validateConfig := func(raw RawConfig) result.Result[Config] {
if raw.IsValid() {
return result.Of(raw.ToConfig())
}
return result.Left[Config](errors.New("invalid"))
}
transform := effect.LocalResultK[string](validateConfig)
adapted := transform(configEffect)
func LocalThunkK ¶
LocalThunkK transforms the context using a Thunk (ReaderIOResult) function. This allows the context transformation to depend on context.Context, perform I/O, and handle errors.
Type Parameters ¶
- A: The value type produced by the effect
- C1: The inner context type (what the effect needs)
- C2: The outer context type (what you have)
Parameters ¶
- f: A Thunk function that transforms C2 to C1
Returns ¶
- func(Effect[C1, A]) Effect[C2, A]: A function that adapts the effect
Example ¶
loadConfig := func(path string) readerioresult.ReaderIOResult[Config] {
return func(ctx context.Context) ioresult.IOResult[Config] {
// load from file with context, may fail
}
}
transform := effect.LocalThunkK[string](loadConfig)
adapted := transform(configEffect)
func Provide ¶
func Provide[A, C any](c C) func(Effect[C, A]) ReaderIOResult[A]
Provide supplies a context to an effect, converting it to a Thunk. This is the first step in running an effect - it eliminates the context dependency by providing the required context value.
Type Parameters ¶
- C: The context type required by the effect
- A: The type of the success value
Parameters ¶
- c: The context value to provide to the effect
Returns ¶
- func(Effect[C, A]) ReaderIOResult[A]: A function that converts an effect to a thunk
Example ¶
ctx := MyContext{APIKey: "secret"}
eff := effect.Of[MyContext](42)
thunk := effect.Provide[MyContext, int](ctx)(eff)
// thunk is now a ReaderIOResult[int] that can be run
func Read ¶
func Read[A, C any](c C) func(Effect[C, A]) Thunk[A]
Read provides a context to an effect, partially applying it. This converts an Effect[C, A] to a Thunk[A] by supplying the required context.
Type Parameters ¶
- A: The type of the success value
- C: The context type
Parameters ¶
- c: The context to provide to the effect
Returns ¶
- func(Effect[C, A]) Thunk[A]: A function that converts an effect to a thunk
Example ¶
ctx := MyContext{Value: "test"}
eff := effect.Of[MyContext](42)
thunk := effect.Read[int](ctx)(eff)
// thunk is now a Thunk[int] that can be run without context
func RunSync ¶
func RunSync[A any](fa ReaderIOResult[A]) readerresult.ReaderResult[A]
RunSync executes a Thunk synchronously, converting it to a standard Go function. This is the final step in running an effect - it executes the IO operations and returns the result as a standard (value, error) tuple.
Type Parameters ¶
- A: The type of the success value
Parameters ¶
- fa: The thunk to execute
Returns ¶
- readerresult.ReaderResult[A]: A function that takes a context.Context and returns (A, error)
Example ¶
ctx := MyContext{APIKey: "secret"}
eff := effect.Of[MyContext](42)
thunk := effect.Provide[MyContext, int](ctx)(eff)
readerResult := effect.RunSync(thunk)
value, err := readerResult(context.Background())
// value == 42, err == nil
Complete Example ¶
// Typical usage pattern: result, err := effect.RunSync( effect.Provide[MyContext, string](myContext)(myEffect), )(context.Background())
Types ¶
type Effect ¶
type Effect[C, A any] = readerreaderioresult.ReaderReaderIOResult[C, A]
Effect represents an effectful computation that:
- Requires a context of type C
- Can perform I/O operations
- Can fail with an error
- Produces a value of type A on success
This is the core type of the effect package, providing a complete effect system for managing dependencies, errors, and side effects in a composable way.
func Do ¶
func Do[C, S any]( empty S, ) Effect[C, S]
Do creates an Effect with an initial state value. This is the starting point for do-notation style effect composition, allowing you to build up complex state transformations step by step.
Type Parameters ¶
- C: The context type required by the effect
- S: The state type
Parameters ¶
- empty: The initial state value
Returns ¶
- Effect[C, S]: An effect that produces the initial state
Example ¶
type State struct {
Name string
Age int
}
eff := effect.Do[MyContext](State{})
func Fail ¶
Fail creates a failed Effect with the given error. This is used to represent computations that have failed.
Type Parameters ¶
- C: The context type required by the effect
- A: The type of the success value (never produced)
Parameters ¶
- err: The error that caused the failure
Returns ¶
- Effect[C, A]: An effect that always fails with the given error
Example ¶
eff := effect.Fail[MyContext, int](errors.New("failed"))
_, err := runEffect(eff, myContext)
// err == errors.New("failed")
func FromThunk ¶ added in v2.2.21
func FromThunk[C, A any](f Thunk[A]) Effect[C, A]
FromThunk lifts a Thunk (context-independent IO computation with error handling) into an Effect. This allows you to integrate computations that don't need the effect's context type C into effect chains. The Thunk will be executed with the runtime context when the effect runs.
Type Parameters ¶
- C: The context type required by the effect (not used by the thunk)
- A: The type of the success value
Parameters ¶
- f: A Thunk[A] that performs IO with error handling
Returns ¶
- Effect[C, A]: An effect that ignores its context and executes the thunk
Example ¶
thunk := func(ctx context.Context) io.IO[result.Result[int]] {
return func() result.Result[int] {
// Perform IO operation
return result.Of(42)
}
}
eff := effect.FromThunk[MyContext](thunk)
// eff can be used in any context but executes the thunk
func Of ¶
func Of[C, A any](a A) Effect[C, A]
Of creates a successful Effect that produces the given value. This is an alias for Succeed and follows the pointed functor convention.
Type Parameters ¶
- C: The context type required by the effect
- A: The type of the success value
Parameters ¶
- a: The value to wrap in a successful effect
Returns ¶
- Effect[C, A]: An effect that always succeeds with the given value
Example ¶
eff := effect.Of[MyContext]("hello")
result, err := runEffect(eff, myContext)
// result == "hello", err == nil
func Retrying ¶
func Retrying[C, A any]( policy retry.RetryPolicy, action Kleisli[C, retry.RetryStatus, A], check Predicate[Result[A]], ) Effect[C, A]
Retrying executes an effect with retry logic based on a policy and check predicate. The effect is retried according to the policy until either:
- The effect succeeds and the check predicate returns false
- The retry policy is exhausted
Type Parameters ¶
- C: The context type required by the effect
- A: The type of the success value
Parameters ¶
- policy: The retry policy defining retry limits and delays
- action: An effectful computation that receives retry status and produces a value
- check: A predicate that determines if the result should trigger a retry
Returns ¶
- Effect[C, A]: An effect that retries according to the policy
Example ¶
policy := retry.LimitRetries(3)
eff := effect.Retrying[MyContext, string](
policy,
func(status retry.RetryStatus) Effect[MyContext, string] {
return fetchData() // may fail
},
func(result Result[string]) bool {
return result.IsLeft() // retry on error
},
)
// Retries up to 3 times if fetchData fails
func Succeed ¶
func Succeed[C, A any](a A) Effect[C, A]
Succeed creates a successful Effect that produces the given value. This is the primary way to lift a pure value into the Effect context.
Type Parameters ¶
- C: The context type required by the effect
- A: The type of the success value
Parameters ¶
- a: The value to wrap in a successful effect
Returns ¶
- Effect[C, A]: An effect that always succeeds with the given value
Example ¶
eff := effect.Succeed[MyContext](42) result, err := runEffect(eff, myContext) // result == 42, err == nil
func Suspend ¶
func Suspend[C, A any](fa Lazy[Effect[C, A]]) Effect[C, A]
Suspend delays the evaluation of an effect until it is run. This is useful for recursive effects or when you need lazy evaluation.
Type Parameters ¶
- C: The context type required by the effect
- A: The type of the success value
Parameters ¶
- fa: A lazy computation that produces an effect
Returns ¶
- Effect[C, A]: An effect that evaluates the lazy computation when run
Example ¶
var recursiveEff func(int) Effect[MyContext, int]
recursiveEff = func(n int) Effect[MyContext, int] {
if n <= 0 {
return effect.Of[MyContext](0)
}
return effect.Suspend(func() Effect[MyContext, int] {
return effect.Map[MyContext](func(x int) int {
return x + n
})(recursiveEff(n - 1))
})
}
type IOEither ¶
IOEither represents a synchronous side effect that can fail with error E or succeed with value A.
type IOResult ¶
IOResult represents a synchronous side effect that can fail with an error or succeed with value A.
type Kleisli ¶
type Kleisli[C, A, B any] = readerreaderioresult.Kleisli[C, A, B]
Kleisli represents a function from A to Effect[C, B], enabling monadic composition. It's the fundamental building block for chaining effectful computations.
func Contramap ¶
func Contramap[A, C1, C2 any](acc Reader[C1, C2]) Kleisli[C1, Effect[C2, A], A]
Contramap is an alias for Local, following the contravariant functor naming convention. It transforms the context required by an effect using a pure function.
Type Parameters ¶
- C1: The outer context type (what you have)
- C2: The inner context type (what the effect needs)
- A: The value type produced by the effect
Parameters ¶
- acc: A pure function that transforms C1 to C2
Returns ¶
- Kleisli[C1, Effect[C2, A], A]: A function that adapts the effect to use C1
func Local ¶
func Local[A, C1, C2 any](acc Reader[C1, C2]) Kleisli[C1, Effect[C2, A], A]
Local transforms the context required by an effect using a pure function. This allows you to adapt an effect that requires one context type to work with a different context type by providing a transformation function.
Type Parameters ¶
- C1: The outer context type (what you have)
- C2: The inner context type (what the effect needs)
- A: The value type produced by the effect
Parameters ¶
- acc: A pure function that transforms C1 to C2
Returns ¶
- Kleisli[C1, Effect[C2, A], A]: A function that adapts the effect to use C1
Example ¶
type AppConfig struct { DB DatabaseConfig }
type DatabaseConfig struct { Host string }
dbEffect := effect.Of[DatabaseConfig]("connected")
appEffect := effect.Local[AppConfig, DatabaseConfig, string](
func(app AppConfig) DatabaseConfig { return app.DB },
)(dbEffect)
func Ternary ¶
func Ternary[C, A, B any](pred Predicate[A], onTrue, onFalse Kleisli[C, A, B]) Kleisli[C, A, B]
Ternary creates a conditional effect based on a predicate. If the predicate returns true, onTrue is executed; otherwise, onFalse is executed.
Type Parameters ¶
- C: The context type required by the effects
- A: The input value type
- B: The output value type
Parameters ¶
- pred: A predicate function to test the input value
- onTrue: The effect to execute if the predicate is true
- onFalse: The effect to execute if the predicate is false
Returns ¶
- Kleisli[C, A, B]: A function that conditionally executes one of two effects
Example ¶
kleisli := effect.Ternary(
func(x int) bool { return x > 10 },
func(x int) Effect[MyContext, string] {
return effect.Of[MyContext]("large")
},
func(x int) Effect[MyContext, string] {
return effect.Of[MyContext]("small")
},
)
result := kleisli(15) // produces "large"
func TraverseArray ¶
func TraverseArray[C, A, B any](f Kleisli[C, A, B]) Kleisli[C, []A, []B]
TraverseArray applies an effectful function to each element of an array, collecting the results into a new array. If any effect fails, the entire traversal fails and returns the first error encountered.
This is useful for performing effectful operations on collections while maintaining the sequential order of results.
Type Parameters ¶
- C: The context type required by the effects
- A: The input element type
- B: The output element type
Parameters ¶
- f: An effectful function to apply to each element
Returns ¶
- Kleisli[C, []A, []B]: A function that transforms an array of A to an effect producing an array of B
Example ¶
parseIntEff := func(s string) Effect[MyContext, int] {
val, err := strconv.Atoi(s)
if err != nil {
return effect.Fail[MyContext, int](err)
}
return effect.Of[MyContext](val)
}
input := []string{"1", "2", "3"}
eff := effect.TraverseArray[MyContext](parseIntEff)(input)
// eff produces []int{1, 2, 3}
type Monoid ¶
Monoid represents an algebraic structure with an associative binary operation and an identity element.
func AlternativeMonoid ¶
AlternativeMonoid creates a monoid for effects using alternative semantics. This tries the first effect, and if it fails, tries the second effect. If both succeed, their results are combined using the provided monoid.
Type Parameters ¶
- C: The context type required by the effects
- A: The value type that has a monoid instance
Parameters ¶
- m: The monoid instance for combining values of type A
Returns ¶
- Monoid[Effect[C, A]]: A monoid for combining effects with fallback behavior
Example ¶
stringMonoid := monoid.MakeMonoid(
func(a, b string) string { return a + b },
"",
)
effectMonoid := effect.AlternativeMonoid[MyContext](stringMonoid)
eff1 := effect.Fail[MyContext, string](errors.New("failed"))
eff2 := effect.Of[MyContext]("fallback")
combined := effectMonoid.Concat(eff1, eff2)
// combined produces "fallback" (first failed, so second is used)
func ApplicativeMonoid ¶
ApplicativeMonoid creates a monoid for effects using applicative semantics. This combines effects by running both and combining their results using the provided monoid. If either effect fails, the combined effect fails.
Type Parameters ¶
- C: The context type required by the effects
- A: The value type that has a monoid instance
Parameters ¶
- m: The monoid instance for combining values of type A
Returns ¶
- Monoid[Effect[C, A]]: A monoid for combining effects
Example ¶
stringMonoid := monoid.MakeMonoid(
func(a, b string) string { return a + b },
"",
)
effectMonoid := effect.ApplicativeMonoid[MyContext](stringMonoid)
eff1 := effect.Of[MyContext]("Hello")
eff2 := effect.Of[MyContext](" World")
combined := effectMonoid.Concat(eff1, eff2)
// combined produces "Hello World"
type Operator ¶
type Operator[C, A, B any] = readerreaderioresult.Operator[C, A, B]
Operator represents a function that transforms Effect[C, A] to Effect[C, B]. It's used for lifting operations over effects.
func Ap ¶
func Ap[B, C, A any](fa Effect[C, A]) Operator[C, func(A) B, B]
Ap applies a function wrapped in an Effect to a value wrapped in an Effect. This is the applicative apply operation, useful for applying effects in parallel.
Type Parameters ¶
- B: The output value type
- C: The context type required by the effects
- A: The input value type
Parameters ¶
- fa: The effect containing the value to apply the function to
Returns ¶
- Operator[C, func(A) B, B]: A function that applies the function effect to the value effect
Example ¶
fnEff := effect.Of[MyContext](func(x int) int { return x * 2 })
valEff := effect.Of[MyContext](21)
result := effect.Ap[int](valEff)(fnEff)
// result produces 42
func ApEitherSL ¶
func ApIOEitherS ¶
func ApIOEitherSL ¶
func ApIOS ¶
func ApIOS[C, S1, S2, T any]( setter func(T) func(S1) S2, fa IO[T], ) Operator[C, S1, S2]
func ApReaderIOS ¶
func ApReaderIOS[C, S1, S2, T any]( setter func(T) func(S1) S2, fa ReaderIO[C, T], ) Operator[C, S1, S2]
func ApReaderIOSL ¶
func ApReaderIOSL[C, S, T any]( lens Lens[S, T], fa ReaderIO[C, T], ) Operator[C, S, S]
func ApReaderS ¶
func ApReaderS[C, S1, S2, T any]( setter func(T) func(S1) S2, fa Reader[C, T], ) Operator[C, S1, S2]
func ApReaderSL ¶
func ApReaderSL[C, S, T any]( lens Lens[S, T], fa Reader[C, T], ) Operator[C, S, S]
func ApS ¶
func ApS[C, S1, S2, T any]( setter func(T) func(S1) S2, fa Effect[C, T], ) Operator[C, S1, S2]
ApS applies an effect and binds its result to the state using a setter function. This is similar to Bind but takes a pre-existing effect rather than a function that creates an effect from the state.
Type Parameters ¶
- C: The context type required by the effects
- S1: The input state type
- S2: The output state type
- T: The type of value produced by the effect
Parameters ¶
- setter: A function that takes the effect result and returns a state updater
- fa: The effect to apply
Returns ¶
- Operator[C, S1, S2]: A function that transforms the state effect
Example ¶
ageEffect := effect.Of[MyContext](30)
eff := effect.ApS(
func(age int) func(State) State {
return func(s State) State {
s.Age = age
return s
}
},
ageEffect,
)(stateEff)
func ApSL ¶
func ApSL[C, S, T any]( lens Lens[S, T], fa Effect[C, T], ) Operator[C, S, S]
ApSL applies an effect and updates a field in the state using a lens. This provides a more ergonomic way to update nested state structures.
Type Parameters ¶
- C: The context type required by the effects
- S: The state type
- T: The type of the field being updated
Parameters ¶
- lens: A lens focusing on the field to update
- fa: The effect producing the new field value
Returns ¶
- Operator[C, S, S]: A function that updates the state field
Example ¶
ageLens := lens.MakeLens(
func(s State) int { return s.Age },
func(s State, age int) State { s.Age = age; return s },
)
ageEffect := effect.Of[MyContext](30)
eff := effect.ApSL(ageLens, ageEffect)(stateEff)
func Bind ¶
func Bind[C, S1, S2, T any]( setter func(T) func(S1) S2, f Kleisli[C, S1, T], ) Operator[C, S1, S2]
Bind executes an effectful computation and binds its result to the state. This is the core operation for do-notation, allowing you to sequence effects while accumulating results in a state structure.
Type Parameters ¶
- C: The context type required by the effects
- S1: The input state type
- S2: The output state type
- T: The type of value produced by the effect
Parameters ¶
- setter: A function that takes the effect result and returns a state updater
- f: An effectful computation that depends on the current state
Returns ¶
- Operator[C, S1, S2]: A function that transforms the state effect
Example ¶
eff := effect.Bind(
func(age int) func(State) State {
return func(s State) State {
s.Age = age
return s
}
},
func(s State) Effect[MyContext, int] {
return effect.Of[MyContext](30)
},
)(effect.Do[MyContext](State{}))
func BindEitherK ¶
func BindIOEitherK ¶
func BindIOEitherKL ¶
func BindIOResultK ¶
func BindL ¶
func BindL[C, S, T any]( lens Lens[S, T], f func(T) Effect[C, T], ) Operator[C, S, S]
BindL executes an effectful computation on a field and updates it using a lens. The effect function receives the current field value and produces a new value.
Type Parameters ¶
- C: The context type required by the effects
- S: The state type
- T: The type of the field being updated
Parameters ¶
- lens: A lens focusing on the field to update
- f: An effectful function that transforms the field value
Returns ¶
- Operator[C, S, S]: A function that updates the state field
Example ¶
ageLens := lens.MakeLens(
func(s State) int { return s.Age },
func(s State, age int) State { s.Age = age; return s },
)
eff := effect.BindL(
ageLens,
func(age int) Effect[MyContext, int] {
return effect.Of[MyContext](age + 1)
},
)(stateEff)
func BindReaderIOK ¶
func BindReaderIOKL ¶
func BindReaderK ¶
func BindReaderKL ¶
func BindTo ¶
func BindTo[C, S1, T any]( setter func(T) S1, ) Operator[C, T, S1]
BindTo wraps a value in an initial state structure. This is typically used to start a bind chain by converting a simple value into a state structure.
Type Parameters ¶
- C: The context type required by the effect
- S1: The state type to create
- T: The type of the input value
Parameters ¶
- setter: A function that creates a state from the value
Returns ¶
- Operator[C, T, S1]: A function that wraps the value in state
Example ¶
eff := effect.BindTo[MyContext](func(name string) State {
return State{Name: name}
})(effect.Of[MyContext]("Alice"))
func Chain ¶
func Chain[C, A, B any](f Kleisli[C, A, B]) Operator[C, A, B]
Chain sequences two effects, where the second effect depends on the result of the first. This is the monadic bind operation (flatMap) for effects. If the first effect fails, the second is not executed.
Type Parameters ¶
- C: The context type required by the effects
- A: The input value type
- B: The output value type
Parameters ¶
- f: A function that takes the result of the first effect and returns a new effect
Returns ¶
- Operator[C, A, B]: A function that transforms Effect[C, A] to Effect[C, B]
Example ¶
eff := effect.Of[MyContext](42)
chained := effect.Chain[MyContext](func(x int) Effect[MyContext, string] {
return effect.Of[MyContext](strconv.Itoa(x * 2))
})(eff)
// chained produces "84"
func ChainFirstIOK ¶ added in v2.2.22
ChainFirstIOK chains an effect with a function that returns an IO action, but discards the result and returns the original value. This is useful for performing side effects (like logging) without changing the value.
Type Parameters ¶
- C: The context type required by the effect
- A: The value type (preserved)
- B: The type produced by the IO action (discarded)
Parameters ¶
- f: A function that takes A and returns IO[B] for side effects
Returns ¶
- Operator[C, A, A]: A function that executes the IO action but preserves the original value
Example ¶
logValue := func(n int) io.IO[any] {
return func() any {
fmt.Printf("Processing: %d\n", n)
return nil
}
}
eff := effect.Of[MyContext](42)
logged := effect.ChainFirstIOK[MyContext](logValue)(eff)
// Prints "Processing: 42" but still produces 42
func ChainIOK ¶ added in v2.2.22
ChainIOK chains an effect with a function that returns an IO action. This is useful for integrating IO-based computations (synchronous side effects) into effect chains. The IO action is automatically lifted into the Effect context.
Type Parameters ¶
- C: The context type required by the effect
- A: The input value type
- B: The output value type
Parameters ¶
- f: A function that takes A and returns IO[B]
Returns ¶
- Operator[C, A, B]: A function that chains the IO-returning function with the effect
Example ¶
performIO := func(n int) io.IO[string] {
return func() string {
// Perform synchronous side effect
return fmt.Sprintf("Value: %d", n)
}
}
eff := effect.Of[MyContext](42)
chained := effect.ChainIOK[MyContext](performIO)(eff)
// chained produces "Value: 42"
func ChainReaderIOK ¶ added in v2.2.21
ChainReaderIOK chains an effect with a function that returns a ReaderIO. This is useful for integrating ReaderIO-based computations (context-dependent IO operations) into effect chains. The ReaderIO is automatically lifted into the Effect context.
Type Parameters ¶
- C: The context type required by the effect
- A: The input value type
- B: The output value type
Parameters ¶
- f: A function that takes A and returns ReaderIO[C, B]
Returns ¶
- Operator[C, A, B]: A function that chains the ReaderIO-returning function with the effect
Example ¶
type Config struct { LogPrefix string }
logAndDouble := func(n int) readerio.ReaderIO[Config, int] {
return func(cfg Config) io.IO[int] {
return func() int {
fmt.Printf("%s: %d\n", cfg.LogPrefix, n)
return n * 2
}
}
}
eff := effect.Of[Config](21)
chained := effect.ChainReaderIOK[Config](logAndDouble)(eff)
// Logs "prefix: 21" and produces 42
func ChainReaderK ¶ added in v2.2.21
ChainReaderK chains an effect with a function that returns a Reader. This is useful for integrating Reader-based computations (pure context-dependent functions) into effect chains. The Reader is automatically lifted into the Effect context.
Type Parameters ¶
- C: The context type required by the effect
- A: The input value type
- B: The output value type
Parameters ¶
- f: A function that takes A and returns Reader[C, B]
Returns ¶
- Operator[C, A, B]: A function that chains the Reader-returning function with the effect
Example ¶
type Config struct { Multiplier int }
getMultiplied := func(n int) reader.Reader[Config, int] {
return func(cfg Config) int {
return n * cfg.Multiplier
}
}
eff := effect.Of[Config](5)
chained := effect.ChainReaderK[Config](getMultiplied)(eff)
// With Config{Multiplier: 3}, produces 15
func ChainResultK ¶
ChainResultK chains an effect with a function that returns a Result. This is useful for integrating Result-based computations into effect chains.
Type Parameters ¶
- C: The context type required by the effect
- A: The input value type
- B: The output value type
Parameters ¶
- f: A function that takes A and returns Result[B]
Returns ¶
- Operator[C, A, B]: A function that chains the Result-returning function with the effect
Example ¶
parseIntResult := result.Eitherize1(strconv.Atoi)
eff := effect.Of[MyContext]("42")
chained := effect.ChainResultK[MyContext](parseIntResult)(eff)
// chained produces 42 as an int
func ChainThunkK ¶ added in v2.2.21
ChainThunkK chains an effect with a function that returns a Thunk. This is useful for integrating Thunk-based computations (context-independent IO with error handling) into effect chains. The Thunk is automatically lifted into the Effect context.
Type Parameters ¶
- C: The context type required by the effect
- A: The input value type
- B: The output value type
Parameters ¶
- f: A function that takes A and returns Thunk[B] (readerioresult.Kleisli[A, B])
Returns ¶
- Operator[C, A, B]: A function that chains the Thunk-returning function with the effect
Example ¶
performIO := func(n int) readerioresult.ReaderIOResult[string] {
return func(ctx context.Context) io.IO[result.Result[string]] {
return func() result.Result[string] {
// Perform IO operation that doesn't need effect context
return result.Of(fmt.Sprintf("Processed: %d", n))
}
}
}
eff := effect.Of[MyContext](42)
chained := effect.ChainThunkK[MyContext](performIO)(eff)
// chained produces "Processed: 42"
func Let ¶
func Let[C, S1, S2, T any]( setter func(T) func(S1) S2, f func(S1) T, ) Operator[C, S1, S2]
Let computes a pure value from the current state and binds it to the state. Unlike Bind, this doesn't perform any effects - it's for pure computations.
Type Parameters ¶
- C: The context type required by the effect
- S1: The input state type
- S2: The output state type
- T: The type of computed value
Parameters ¶
- setter: A function that takes the computed value and returns a state updater
- f: A pure function that computes a value from the current state
Returns ¶
- Operator[C, S1, S2]: A function that transforms the state effect
Example ¶
eff := effect.Let[MyContext](
func(nameLen int) func(State) State {
return func(s State) State {
s.NameLength = nameLen
return s
}
},
func(s State) int {
return len(s.Name)
},
)(stateEff)
func LetL ¶
func LetL[C, S, T any]( lens Lens[S, T], f func(T) T, ) Operator[C, S, S]
LetL computes a new field value from the current value using a lens. This is a pure transformation of a field within the state.
Type Parameters ¶
- C: The context type required by the effect
- S: The state type
- T: The type of the field being updated
Parameters ¶
- lens: A lens focusing on the field to update
- f: A pure function that transforms the field value
Returns ¶
- Operator[C, S, S]: A function that updates the state field
Example ¶
ageLens := lens.MakeLens(
func(s State) int { return s.Age },
func(s State, age int) State { s.Age = age; return s },
)
eff := effect.LetL[MyContext](
ageLens,
func(age int) int { return age * 2 },
)(stateEff)
func LetTo ¶
func LetTo[C, S1, S2, T any]( setter func(T) func(S1) S2, b T, ) Operator[C, S1, S2]
LetTo binds a constant value to the state. This is useful for setting fixed values in your state structure.
Type Parameters ¶
- C: The context type required by the effect
- S1: The input state type
- S2: The output state type
- T: The type of the constant value
Parameters ¶
- setter: A function that takes the constant and returns a state updater
- b: The constant value to bind
Returns ¶
- Operator[C, S1, S2]: A function that transforms the state effect
Example ¶
eff := effect.LetTo[MyContext](
func(age int) func(State) State {
return func(s State) State {
s.Age = age
return s
}
},
42,
)(stateEff)
func LetToL ¶
func LetToL[C, S, T any]( lens Lens[S, T], b T, ) Operator[C, S, S]
LetToL sets a field to a constant value using a lens.
Type Parameters ¶
- C: The context type required by the effect
- S: The state type
- T: The type of the field being updated
Parameters ¶
- lens: A lens focusing on the field to update
- b: The constant value to set
Returns ¶
- Operator[C, S, S]: A function that updates the state field
Example ¶
ageLens := lens.MakeLens(
func(s State) int { return s.Age },
func(s State, age int) State { s.Age = age; return s },
)
eff := effect.LetToL[MyContext](ageLens, 42)(stateEff)
func Map ¶
func Map[C, A, B any](f func(A) B) Operator[C, A, B]
Map transforms the success value of an Effect using the provided function. If the effect fails, the error is propagated unchanged.
Type Parameters ¶
- C: The context type required by the effect
- A: The input value type
- B: The output value type
Parameters ¶
- f: The transformation function to apply to the success value
Returns ¶
- Operator[C, A, B]: A function that transforms Effect[C, A] to Effect[C, B]
Example ¶
eff := effect.Of[MyContext](42)
mapped := effect.Map[MyContext](func(x int) string {
return strconv.Itoa(x)
})(eff)
// mapped produces "42"
func Tap ¶
func Tap[C, A, ANY any](f Kleisli[C, A, ANY]) Operator[C, A, A]
Tap executes a side effect for its effect, but returns the original value. This is useful for logging, debugging, or performing actions without changing the result.
Type Parameters ¶
- C: The context type required by the effects
- A: The value type
- ANY: The type produced by the side effect (ignored)
Parameters ¶
- f: A function that performs a side effect based on the value
Returns ¶
- Operator[C, A, A]: A function that executes the side effect but preserves the original value
Example ¶
eff := effect.Of[MyContext](42)
tapped := effect.Tap[MyContext](func(x int) Effect[MyContext, any] {
fmt.Println("Value:", x)
return effect.Of[MyContext, any](nil)
})(eff)
// Prints "Value: 42" but still produces 42
func TapIOK ¶ added in v2.2.22
TapIOK is an alias for ChainFirstIOK. It chains an effect with a function that returns an IO action for side effects, but preserves the original value. This is useful for logging, debugging, or performing actions without changing the result.
Type Parameters ¶
- C: The context type required by the effect
- A: The value type (preserved)
- B: The type produced by the IO action (discarded)
Parameters ¶
- f: A function that takes A and returns IO[B] for side effects
Returns ¶
- Operator[C, A, A]: A function that executes the IO action but preserves the original value
Example ¶
logValue := func(n int) io.IO[any] {
return func() any {
fmt.Printf("Value: %d\n", n)
return nil
}
}
eff := effect.Of[MyContext](42)
tapped := effect.TapIOK[MyContext](logValue)(eff)
// Prints "Value: 42" but still produces 42
type Predicate ¶
Predicate represents a function that tests a value of type A and returns a boolean.
type ReaderIO ¶
ReaderIO represents a computation that depends on a context R and produces an IO action returning A.
type ReaderIOResult ¶
type ReaderIOResult[A any] = readerioresult.ReaderIOResult[A]
ReaderIOResult represents a computation that depends on context and performs IO with error handling.
type Result ¶
Result represents a computation result that can be either an error (Left) or a success value (Right).
type Thunk ¶
type Thunk[A any] = ReaderIOResult[A]
Thunk represents a computation that performs IO with error handling but doesn't require context. It's equivalent to ReaderIOResult and is used as an intermediate step when providing context to an Effect.