effect

package
v2.2.22 Latest Latest
Warning

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

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

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

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

func LocalIOK[A, C1, C2 any](f io.Kleisli[C2, C1]) func(Effect[C1, A]) Effect[C2, A]

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

func LocalIOResultK[A, C1, C2 any](f ioresult.Kleisli[C2, C1]) func(Effect[C1, A]) Effect[C2, A]

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

func LocalResultK[A, C1, C2 any](f result.Kleisli[C2, C1]) func(Effect[C1, A]) Effect[C2, A]

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

func LocalThunkK[A, C1, C2 any](f thunk.Kleisli[C2, C1]) func(Effect[C1, A]) Effect[C2, A]

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

func Fail[C, A any](err error) Effect[C, A]

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 Either

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

Either represents a value that can be either a Left (error) or Right (success).

type IO

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

IO represents a synchronous side effect that produces a value A.

type IOEither

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

IOEither represents a synchronous side effect that can fail with error E or succeed with value A.

type IOResult

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

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 Lazy

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

Lazy represents a lazily evaluated computation that produces a value A.

type Lens

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

Lens represents an optic for focusing on a field T within a structure S.

type Monoid

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

Monoid represents an algebraic structure with an associative binary operation and an identity element.

func AlternativeMonoid

func AlternativeMonoid[C, A any](m monoid.Monoid[A]) Monoid[Effect[C, A]]

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

func ApplicativeMonoid[C, A any](m monoid.Monoid[A]) Monoid[Effect[C, A]]

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 ApEitherS

func ApEitherS[C, S1, S2, T any](
	setter func(T) func(S1) S2,
	fa Either[error, T],
) Operator[C, S1, S2]

func ApEitherSL

func ApEitherSL[C, S, T any](
	lens Lens[S, T],
	fa Either[error, T],
) Operator[C, S, S]

func ApIOEitherS

func ApIOEitherS[C, S1, S2, T any](
	setter func(T) func(S1) S2,
	fa IOEither[error, T],
) Operator[C, S1, S2]

func ApIOEitherSL

func ApIOEitherSL[C, S, T any](
	lens Lens[S, T],
	fa IOEither[error, T],
) Operator[C, S, S]

func ApIOS

func ApIOS[C, S1, S2, T any](
	setter func(T) func(S1) S2,
	fa IO[T],
) Operator[C, S1, S2]

func ApIOSL

func ApIOSL[C, S, T any](
	lens Lens[S, T],
	fa IO[T],
) Operator[C, S, S]

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

func BindIOEitherK

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

func BindIOEitherKL[C, S, T any](
	lens Lens[S, T],
	f ioeither.Kleisli[error, T, T],
) Operator[C, S, S]

func BindIOK

func BindIOK[C, S1, S2, T any](
	setter func(T) func(S1) S2,
	f io.Kleisli[S1, T],
) Operator[C, S1, S2]

func BindIOKL

func BindIOKL[C, S, T any](
	lens Lens[S, T],
	f io.Kleisli[T, T],
) Operator[C, S, S]

func BindIOResultK

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

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

func BindReaderIOKL

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

func BindReaderK

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

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

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

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

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

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

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

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

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

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

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

func ChainResultK[C, A, B any](f result.Kleisli[A, B]) Operator[C, A, B]

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

func ChainThunkK[C, A, B any](f thunk.Kleisli[A, B]) Operator[C, A, B]

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

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

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

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

Predicate represents a function that tests a value of type A and returns a boolean.

type Reader

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

Reader represents a computation that depends on a context R and produces a value A.

type ReaderIO

type ReaderIO[R, A any] = readerio.ReaderIO[R, A]

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

type Result[A any] = result.Result[A]

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.

Jump to

Keyboard shortcuts

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