either

package
v2.0.3 Latest Latest
Warning

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

Go to latest
Published: Dec 20, 2025 License: Apache-2.0 Imports: 25 Imported by: 0

Documentation

Overview

Package either provides the Either monad, a data structure representing a value of one of two possible types.

Either is commonly used for error handling, where by convention:

  • Left represents an error or failure case (type E)
  • Right represents a success case (type A)

Fantasy Land Specification

This implementation corresponds to the Fantasy Land Either type: https://github.com/fantasyland/fantasy-land#either

Implemented Fantasy Land algebras:

Core Concepts

The Either type is a discriminated union that can hold either a Left value (typically an error) or a Right value (typically a successful result). This makes it ideal for computations that may fail.

Basic Usage

// Creating Either values
success := either.Right[error](42)           // Right value
failure := either.Left[int](errors.New("oops")) // Left value

// Pattern matching with Fold
result := either.Fold(
    func(err error) string { return "Error: " + err.Error() },
    func(n int) string { return fmt.Sprintf("Success: %d", n) },
)(success)

// Chaining operations (short-circuits on Left)
result := either.Chain(func(n int) either.Either[error, int] {
    return either.Right[error](n * 2)
})(success)

Monadic Operations

Either implements the Monad interface, providing:

  • Map: Transform the Right value
  • Chain (FlatMap): Chain computations that may fail
  • Ap: Apply a function wrapped in Either

Error Handling

Either provides utilities for working with Go's error type:

  • TryCatchError: Convert (value, error) tuples to Either
  • UnwrapError: Convert Either back to (value, error) tuple
  • FromError: Create Either from error-returning functions

Subpackages

  • either/exec: Execute system commands returning Either
  • either/http: HTTP request builders returning Either
  • either/testing: Testing utilities for Either laws

package either implements the Either monad

A data type that can be of either of two types but not both. This is typically used to carry an error or a return value

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func AltSemigroup

func AltSemigroup[E, A any]() S.Semigroup[Either[E, A]]

AltSemigroup creates a semigroup for Either that uses the Alt operation for combining values. When combining two Either values, it returns the first Right value, or the second value if the first is Left.

Example:

sg := either.AltSemigroup[error, int]()
result := sg.Concat(either.Left[int](errors.New("error")), either.Right[error](42))
// result is Right(42)
result2 := sg.Concat(either.Right[error](1), either.Right[error](2))
// result2 is Right(1) - first Right wins

func AltW

func AltW[E, E1, A any](that Lazy[Either[E1, A]]) func(Either[E, A]) Either[E1, A]

AltW provides an alternative Either if the first is Left, allowing different error types. The 'W' suffix indicates "widening" of the error type.

Example:

alternative := either.AltW[error, string](func() either.Either[string, int] {
    return either.Right[string](99)
})
result := alternative(either.Left[int](errors.New("fail"))) // Right(99)

func ApV

func ApV[B, A, E any](sg S.Semigroup[E]) func(Either[E, A]) Operator[E, func(A) B, B]

ApV is the curried version of MonadApV that combines errors using a semigroup.

This function provides a more convenient API for validation scenarios by currying the arguments. It first takes the value to validate, then returns a function that takes the validation function. This allows for a more natural composition style.

Like MonadApV, this accumulates all errors using the provided semigroup instead of short-circuiting on the first error. This is the key difference from the standard Ap function.

Type Parameters:

  • B: The result type after applying the function
  • E: The error type (must support the semigroup operation)
  • A: The input type to the function

Parameters:

  • sg: A semigroup that defines how to combine two error values

Returns:

  • A function that takes a value Either[E, A] and returns an Operator that applies validation functions while accumulating errors

Example:

// Define a semigroup for combining validation errors
type ValidationError struct {
    Errors []string
}
errorSemigroup := semigroup.MakeSemigroup(func(e1, e2 ValidationError) ValidationError {
    return ValidationError{Errors: append(e1.Errors, e2.Errors...)}
})

// Create validators
validatePositive := func(x int) either.Either[ValidationError, int] {
    if x > 0 {
        return either.Right[ValidationError](x)
    }
    return either.Left[int](ValidationError{Errors: []string{"must be positive"}})
}

// Use ApV for validation
applyValidation := either.ApV[int](errorSemigroup)
value := either.Left[int](ValidationError{Errors: []string{"invalid input"}})
validator := either.Left[func(int) int](ValidationError{Errors: []string{"invalid validator"}})

result := applyValidation(value)(validator)
// Left(ValidationError{Errors: []string{"invalid validator", "invalid input"}})

func Applicative

func Applicative[E, A, B any]() applicative.Applicative[A, B, Either[E, A], Either[E, B], Either[E, func(A) B]]

Applicative creates a standard Applicative instance for Either with fail-fast error handling.

This returns a lawful Applicative that satisfies all applicative laws:

  • Identity: Ap(Of(identity))(v) == v
  • Homomorphism: Ap(Of(f))(Of(x)) == Of(f(x))
  • Interchange: Ap(Of(f))(u) == Ap(Map(f => f(y))(u))(Of(y))
  • Composition: Ap(Ap(Map(compose)(f))(g))(x) == Ap(f)(Ap(g)(x))

The Applicative operations behave as follows:

  • Of: lifts a value into Right
  • Map: transforms Right values, preserves Left (standard functor)
  • Ap: fails fast - if either operand is Left, returns the first Left encountered

This is the standard Either applicative that stops at the first error, making it suitable for computations where you want to short-circuit on failure.

Example - Fail-Fast Behavior:

app := either.Applicative[error, int, string]()

// Both succeed - function application works
value := either.Right[error](42)
fn := either.Right[error](strconv.Itoa)
result := app.Ap(value)(fn)
// result is Right("42")

// First error stops computation
err1 := either.Left[func(int) string](errors.New("error 1"))
err2 := either.Left[int](errors.New("error 2"))
result2 := app.Ap(err2)(err1)
// result2 is Left(error 1) - only first error is returned

Type Parameters:

  • E: The error type (Left value)
  • A: The input value type (Right value)
  • B: The output value type after transformation

func ApplicativeMonoid

func ApplicativeMonoid[E, A any](m M.Monoid[A]) M.Monoid[Either[E, A]]

ApplicativeMonoid returns a Monoid that concatenates Either instances via their applicative. Provides an empty Either (Right with monoid's empty value) and combines Right values using the monoid.

Example:

intAddMonoid := monoid.MakeMonoid(0, func(a, b int) int { return a + b })
eitherMon := either.ApplicativeMonoid[error](intAddMonoid)
empty := eitherMon.Empty() // Right(0)

func ApplicativeV

func ApplicativeV[E, A, B any](sg S.Semigroup[E]) applicative.Applicative[A, B, Either[E, A], Either[E, B], Either[E, func(A) B]]

ApplicativeV creates an Applicative with validation-style error accumulation.

This returns a lawful Applicative that accumulates errors using a Semigroup when combining independent computations with Ap. This is the "validation" pattern commonly used for form validation, configuration validation, and parallel error collection.

The returned instance satisfies all applicative laws:

  • Identity: Ap(Of(identity))(v) == v
  • Homomorphism: Ap(Of(f))(Of(x)) == Of(f(x))
  • Interchange: Ap(Of(f))(u) == Ap(Map(f => f(y))(u))(Of(y))
  • Composition: Ap(Ap(Map(compose)(f))(g))(x) == Ap(f)(Ap(g)(x))

Key behaviors:

  • Of: lifts a value into Right
  • Map: transforms Right values, preserves Left (standard functor)
  • Ap: when both operands are Left, combines errors using the Semigroup

Comparison with standard Applicative:

  • Applicative: Ap fails fast (returns first error)
  • ApplicativeV: Ap accumulates errors (combines all errors via Semigroup)

Use cases:

  • Form validation: collect all validation errors at once
  • Configuration validation: report all configuration problems
  • Parallel independent checks: accumulate all failures

Example - Error Accumulation for Form Validation:

type ValidationErrors []string

// Define how to combine error lists
sg := semigroup.MakeSemigroup(func(a, b ValidationErrors) ValidationErrors {
    return append(append(ValidationErrors{}, a...), b...)
})

app := either.ApplicativeV[ValidationErrors, User, User](sg)

// Validate multiple fields independently
validateName := func(name string) Either[ValidationErrors, string] {
    if len(name) < 3 {
        return Left[string](ValidationErrors{"Name must be at least 3 characters"})
    }
    return Right[ValidationErrors](name)
}

validateAge := func(age int) Either[ValidationErrors, int] {
    if age < 18 {
        return Left[int](ValidationErrors{"Must be 18 or older"})
    }
    return Right[ValidationErrors](age)
}

validateEmail := func(email string) Either[ValidationErrors, string] {
    if !strings.Contains(email, "@") {
        return Left[string](ValidationErrors{"Invalid email format"})
    }
    return Right[ValidationErrors](email)
}

// Create a constructor function lifted into Either
makeUser := func(name string) func(int) func(string) User {
    return func(age int) func(string) User {
        return func(email string) User {
            return User{Name: name, Age: age, Email: email}
        }
    }
}

// Apply validations - all errors are collected
name := validateName("ab")          // Left: name too short
age := validateAge(16)              // Left: age too low
email := validateEmail("invalid")    // Left: invalid email

// Combine all validations using ApV
result := app.Ap(name)(
    app.Ap(age)(
        app.Ap(email)(
            app.Of(makeUser),
        ),
    ),
)
// result is Left(ValidationErrors{
//     "Name must be at least 3 characters",
//     "Must be 18 or older",
//     "Invalid email format"
// })
// All three errors are collected!

Type Parameters:

  • E: The error type that must have a Semigroup for combining errors
  • A: The input value type (Right value)
  • B: The output value type after transformation
  • sg: Semigroup instance for combining Left values when both operands of Ap are Left

func ApplySemigroup

func ApplySemigroup[E, A any](s S.Semigroup[A]) S.Semigroup[Either[E, A]]

ApplySemigroup lifts a Semigroup over the Right values of Either. Combines two Right values using the provided Semigroup. If either value is Left, returns the first Left encountered.

Example:

intAdd := semigroup.MakeSemigroup(func(a, b int) int { return a + b })
eitherSemi := either.ApplySemigroup[error](intAdd)
result := eitherSemi.Concat(either.Right[error](2), either.Right[error](3)) // Right(5)

func BiMap

func BiMap[E1, E2, A, B any](f func(E1) E2, g func(a A) B) func(Either[E1, A]) Either[E2, B]

BiMap is the curried version of MonadBiMap. Maps a pair of functions over the two type arguments of the bifunctor.

func ChainOptionK

func ChainOptionK[A, B, E any](onNone func() E) func(func(A) Option[B]) Operator[E, A, B]

ChainOptionK is the curried version of MonadChainOptionK.

func CompactArray

func CompactArray[E, A any](fa []Either[E, A]) []A

CompactArray discards all Left values and keeps only the Right values.

Example:

eithers := []either.Either[error, int]{
    either.Right[error](1),
    either.Left[int](errors.New("error")),
    either.Right[error](3),
}
result := either.CompactArray(eithers)
// result is []int{1, 3}

func CompactArrayG

func CompactArrayG[A1 ~[]Either[E, A], A2 ~[]A, E, A any](fa A1) A2

CompactArrayG discards all Left values and keeps only the Right values. The G suffix indicates support for generic slice types.

Example:

eithers := []either.Either[error, int]{
    either.Right[error](1),
    either.Left[int](errors.New("error")),
    either.Right[error](3),
}
result := either.CompactArrayG[[]either.Either[error, int], []int](eithers)
// result is []int{1, 3}

func CompactRecord

func CompactRecord[K comparable, E, A any](m map[K]Either[E, A]) map[K]A

CompactRecord discards all Left values and keeps only the Right values.

Example:

eithers := map[string]either.Either[error, int]{
    "a": either.Right[error](1),
    "b": either.Left[int](errors.New("error")),
    "c": either.Right[error](3),
}
result := either.CompactRecord(eithers)
// result is map[string]int{"a": 1, "c": 3}

func CompactRecordG

func CompactRecordG[M1 ~map[K]Either[E, A], M2 ~map[K]A, K comparable, E, A any](m M1) M2

CompactRecordG discards all Left values and keeps only the Right values. The G suffix indicates support for generic map types.

Example:

eithers := map[string]either.Either[error, int]{
    "a": either.Right[error](1),
    "b": either.Left[int](errors.New("error")),
    "c": either.Right[error](3),
}
result := either.CompactRecordG[map[string]either.Either[error, int], map[string]int](eithers)
// result is map[string]int{"a": 1, "c": 3}

func Curry0

func Curry0[R any](f func() (R, error)) func() Either[error, R]

Curry0 converts a Go function that returns (R, error) into a curried version that returns Either[error, R].

Example:

getConfig := func() (string, error) { return "config", nil }
curried := either.Curry0(getConfig)
result := curried() // Right("config")

func Curry1

func Curry1[T1, R any](f func(T1) (R, error)) func(T1) Either[error, R]

Curry1 converts a Go function that returns (R, error) into a curried version that returns Either[error, R].

Example:

parse := strconv.Atoi
curried := either.Curry1(parse)
result := curried("42") // Right(42)

func Curry2

func Curry2[T1, T2, R any](f func(T1, T2) (R, error)) func(T1) func(T2) Either[error, R]

Curry2 converts a 2-argument Go function that returns (R, error) into a curried version.

Example:

divide := func(a, b int) (int, error) {
    if b == 0 { return 0, errors.New("div by zero") }
    return a / b, nil
}
curried := either.Curry2(divide)
result := curried(10)(2) // Right(5)

func Curry3

func Curry3[T1, T2, T3, R any](f func(T1, T2, T3) (R, error)) func(T1) func(T2) func(T3) Either[error, R]

Curry3 converts a 3-argument Go function that returns (R, error) into a curried version.

func Curry4

func Curry4[T1, T2, T3, T4, R any](f func(T1, T2, T3, T4) (R, error)) func(T1) func(T2) func(T3) func(T4) Either[error, R]

Curry4 converts a 4-argument Go function that returns (R, error) into a curried version.

func Eitherize0

func Eitherize0[F ~func() (R, error), R any](f F) func() Either[error, R]

Eitherize0 converts a function with 0 parameters returning a tuple into a function with 0 parameters returning an Either The inverse function is Uneitherize0

func Eitherize1

func Eitherize1[F ~func(T0) (R, error), T0, R any](f F) func(T0) Either[error, R]

Eitherize1 converts a function with 1 parameters returning a tuple into a function with 1 parameters returning an Either The inverse function is Uneitherize1

func Eitherize10

func Eitherize10[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) Either[error, R]

Eitherize10 converts a function with 10 parameters returning a tuple into a function with 10 parameters returning an Either The inverse function is Uneitherize10

func Eitherize11

func Eitherize11[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) Either[error, R]

Eitherize11 converts a function with 11 parameters returning a tuple into a function with 11 parameters returning an Either The inverse function is Uneitherize11

func Eitherize12

func Eitherize12[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) Either[error, R]

Eitherize12 converts a function with 12 parameters returning a tuple into a function with 12 parameters returning an Either The inverse function is Uneitherize12

func Eitherize13

func Eitherize13[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) Either[error, R]

Eitherize13 converts a function with 13 parameters returning a tuple into a function with 13 parameters returning an Either The inverse function is Uneitherize13

func Eitherize14

func Eitherize14[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) Either[error, R]

Eitherize14 converts a function with 14 parameters returning a tuple into a function with 14 parameters returning an Either The inverse function is Uneitherize14

func Eitherize15

func Eitherize15[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) Either[error, R]

Eitherize15 converts a function with 15 parameters returning a tuple into a function with 15 parameters returning an Either The inverse function is Uneitherize15

func Eitherize2

func Eitherize2[F ~func(T0, T1) (R, error), T0, T1, R any](f F) func(T0, T1) Either[error, R]

Eitherize2 converts a function with 2 parameters returning a tuple into a function with 2 parameters returning an Either The inverse function is Uneitherize2

func Eitherize3

func Eitherize3[F ~func(T0, T1, T2) (R, error), T0, T1, T2, R any](f F) func(T0, T1, T2) Either[error, R]

Eitherize3 converts a function with 3 parameters returning a tuple into a function with 3 parameters returning an Either The inverse function is Uneitherize3

func Eitherize4

func Eitherize4[F ~func(T0, T1, T2, T3) (R, error), T0, T1, T2, T3, R any](f F) func(T0, T1, T2, T3) Either[error, R]

Eitherize4 converts a function with 4 parameters returning a tuple into a function with 4 parameters returning an Either The inverse function is Uneitherize4

func Eitherize5

func Eitherize5[F ~func(T0, T1, T2, T3, T4) (R, error), T0, T1, T2, T3, T4, R any](f F) func(T0, T1, T2, T3, T4) Either[error, R]

Eitherize5 converts a function with 5 parameters returning a tuple into a function with 5 parameters returning an Either The inverse function is Uneitherize5

func Eitherize6

func Eitherize6[F ~func(T0, T1, T2, T3, T4, T5) (R, error), T0, T1, T2, T3, T4, T5, R any](f F) func(T0, T1, T2, T3, T4, T5) Either[error, R]

Eitherize6 converts a function with 6 parameters returning a tuple into a function with 6 parameters returning an Either The inverse function is Uneitherize6

func Eitherize7

func Eitherize7[F ~func(T0, T1, T2, T3, T4, T5, T6) (R, error), T0, T1, T2, T3, T4, T5, T6, R any](f F) func(T0, T1, T2, T3, T4, T5, T6) Either[error, R]

Eitherize7 converts a function with 7 parameters returning a tuple into a function with 7 parameters returning an Either The inverse function is Uneitherize7

func Eitherize8

func Eitherize8[F ~func(T0, T1, T2, T3, T4, T5, T6, T7) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7) Either[error, R]

Eitherize8 converts a function with 8 parameters returning a tuple into a function with 8 parameters returning an Either The inverse function is Uneitherize8

func Eitherize9

func Eitherize9[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8) Either[error, R]

Eitherize9 converts a function with 9 parameters returning a tuple into a function with 9 parameters returning an Either The inverse function is Uneitherize9

func Eq

func Eq[E, A any](e EQ.Eq[E], a EQ.Eq[A]) EQ.Eq[Either[E, A]]

Eq constructs an equality predicate for Either values. Two Either values are equal if they are both Left with equal error values, or both Right with equal success values.

Parameters:

  • e: Equality predicate for the Left (error) type
  • a: Equality predicate for the Right (success) type

Example:

eq := either.Eq(eq.FromStrictEquals[error](), eq.FromStrictEquals[int]())
result := eq.Equals(either.Right[error](42), either.Right[error](42)) // true
result2 := eq.Equals(either.Right[error](42), either.Right[error](43)) // false

func Fold

func Fold[E, A, B any](onLeft func(E) B, onRight func(A) B) func(Either[E, A]) B

Fold is the curried version of MonadFold. Extracts the value from an Either by providing handlers for both cases.

Example:

result := either.Fold(
    func(err error) string { return "Error: " + err.Error() },
    func(n int) string { return fmt.Sprintf("Value: %d", n) },
)(either.Right[error](42)) // "Value: 42"

func FromError

func FromError[A any](f func(a A) error) func(A) Either[error, A]

FromError creates an Either from a function that may return an error.

Example:

validate := func(x int) error {
    if x < 0 { return errors.New("negative") }
    return nil
}
toEither := either.FromError(validate)
result := toEither(42) // Right(42)

func FromNillable

func FromNillable[A, E any](e E) func(*A) Either[E, *A]

FromNillable creates an Either from a pointer, using the provided error for nil pointers.

Example:

var ptr *int = nil
result := either.FromNillable[int](errors.New("nil"))(ptr) // Left(error)
val := 42
result := either.FromNillable[int](errors.New("nil"))(&val) // Right(&42)

func FromOption

func FromOption[A, E any](onNone func() E) func(Option[A]) Either[E, A]

FromOption converts an Option to an Either, using the provided function to generate a Left value for None.

Example:

opt := option.Some(42)
result := either.FromOption[int](func() error { return errors.New("none") })(opt) // Right(42)

func FromPredicate

func FromPredicate[E, A any](pred func(A) bool, onFalse func(A) E) func(A) Either[E, A]

FromPredicate creates an Either based on a predicate. If the predicate returns true, creates a Right; otherwise creates a Left using onFalse.

Example:

isPositive := either.FromPredicate(
    func(x int) bool { return x > 0 },
    func(x int) error { return errors.New("not positive") },
)
result := isPositive(42) // Right(42)
result := isPositive(-1) // Left(error)

func FromStrictEquals

func FromStrictEquals[E, A comparable]() EQ.Eq[Either[E, A]]

FromStrictEquals constructs an equality predicate using Go's == operator. Both the Left and Right types must be comparable.

Example:

eq := either.FromStrictEquals[error, int]()
result := eq.Equals(either.Right[error](42), either.Right[error](42)) // true

func Functor

func Functor[E, A, B any]() functor.Functor[A, B, Either[E, A], Either[E, B]]

Functor implements the functoric operations for Either. A functor provides the Map operation that transforms values inside a context while preserving the structure.

Example:

f := either.Functor[error, int, string]()
result := f.Map(strconv.Itoa)(either.Right[error](42))
// result is Right("42")

func GetOrElse

func GetOrElse[E, A any](onLeft func(E) A) func(Either[E, A]) A

GetOrElse extracts the Right value or computes a default from the Left value.

Example:

result := either.GetOrElse(func(err error) int { return 0 })(either.Right[error](42)) // 42
result := either.GetOrElse(func(err error) int { return 0 })(either.Left[int](err)) // 0

func IsLeft

func IsLeft[E, A any](val Either[E, A]) bool

IsLeft tests if the Either is a Left value. Rather use Fold or MonadFold if you need to access the values. Inverse is IsRight.

Example:

either.IsLeft(either.Left[int](errors.New("err"))) // true
either.IsLeft(either.Right[error](42)) // false

func IsRight

func IsRight[E, A any](val Either[E, A]) bool

IsRight tests if the Either is a Right value. Rather use Fold or MonadFold if you need to access the values. Inverse is IsLeft.

Example:

either.IsRight(either.Right[error](42)) // true
either.IsRight(either.Left[int](errors.New("err"))) // false

func Logger

func Logger[E, A any](loggers ...*log.Logger) func(string) Operator[E, A, A]

Logger creates a logging function for Either values that logs both Left and Right cases. The function logs the value and then returns the original Either unchanged.

Parameters:

  • loggers: Optional log.Logger instances. If none provided, uses default logger.

Example:

logger := either.Logger[error, int]()
result := F.Pipe2(
    either.Right[error](42),
    logger("Processing"),
    either.Map(N.Mul(2)),
)
// Logs: "Processing: 42"
// result is Right(84)

func MapLeft

func MapLeft[A, E1, E2 any](f func(E1) E2) func(fa Either[E1, A]) Either[E2, A]

MapLeft is the curried version of MonadMapLeft. Applies a mapping function to the Left (error) channel.

func Monad

func Monad[E, A, B any]() monad.Monad[A, B, Either[E, A], Either[E, B], Either[E, func(A) B]]

Monad creates a lawful Monad instance for Either with fail-fast error handling.

A monad combines the capabilities of four type classes:

  • Functor (Map): transform the Right value
  • Pointed (Of): lift a pure value into a Right
  • Applicative (Ap): apply wrapped functions (fails fast on first Left)
  • Chainable (Chain): sequence dependent computations (fails fast on first Left)

The Either monad is left-biased and fails fast: once a Left is encountered, no further computations are performed and the Left is propagated immediately. This makes it ideal for error handling where you want to stop at the first error.

This implementation satisfies all monad laws:

Monad Laws:

  • Left Identity: Chain(f)(Of(a)) == f(a)
  • Right Identity: Chain(Of)(m) == m
  • Associativity: Chain(g)(Chain(f)(m)) == Chain(x => Chain(g)(f(x)))(m)

Additionally, it satisfies all prerequisite laws from Functor, Apply, and Applicative.

Relationship to Applicative:

This Monad uses the standard fail-fast Applicative (see Applicative function). In a lawful monad, Ap can be derived from Chain and Of:

Ap(fa)(ff) == Chain(f => Chain(a => Of(f(a)))(fa))(ff)

The Either monad satisfies this property, making it a true lawful monad.

When to use Monad vs Applicative:

  • Use Monad when you need sequential dependent operations (Chain)
  • Use Applicative when you only need independent operations (Ap, Map)
  • Both fail fast on the first error

When to use Monad vs ApplicativeV:

  • Use Monad for sequential error handling (fail-fast)
  • Use ApplicativeV for parallel validation (error accumulation)
  • Note: There is no "MonadV" because Chain inherently fails fast

Example - Sequential Dependent Operations:

m := either.Monad[error, int, string]()

// Chain allows each step to depend on the previous result
result := m.Chain(func(x int) either.Either[error, string] {
    if x > 0 {
        return either.Right[error](strconv.Itoa(x))
    }
    return either.Left[string](errors.New("value must be positive"))
})(either.Right[error](42))
// result is Right("42")

// Fails fast on first error
result2 := m.Chain(func(x int) either.Either[error, string] {
    return either.Right[error](strconv.Itoa(x))
})(either.Left[int](errors.New("initial error")))
// result2 is Left("initial error") - Chain never executes

Example - Combining with Applicative operations:

m := either.Monad[error, int, int]()

// Map transforms the value
value := m.Map(N.Mul(2))(either.Right[error](21))
// value is Right(42)

// Ap applies wrapped functions (also fails fast)
fn := either.Right[error](N.Add(1))
result := m.Ap(value)(fn)
// result is Right(43)

Example - Real-world usage with error handling:

m := either.Monad[error, User, SavedUser]()

// Pipeline of operations that can fail
result := m.Chain(func(user User) either.Either[error, SavedUser] {
    // Save to database
    return saveToDatabase(user)
})(m.Chain(func(user User) either.Either[error, User] {
    // Validate user
    return validateUser(user)
})(either.Right[error](inputUser)))

// If any step fails, the error propagates immediately

Type Parameters:

  • E: The error type (Left value)
  • A: The input value type (Right value)
  • B: The output value type after transformation

func MonadApV

func MonadApV[B, A, E any](sg S.Semigroup[E]) func(fab Either[E, func(a A) B], fa Either[E, A]) Either[E, B]

MonadApV is the applicative validation functor that combines errors using a semigroup.

Unlike the standard MonadAp which short-circuits on the first Left (error), MonadApV accumulates all errors using the provided semigroup's Concat operation. This is particularly useful for validation scenarios where you want to collect all validation errors rather than stopping at the first one.

The function takes a semigroup for combining errors and returns a function that applies a wrapped function to a wrapped value, accumulating errors if both are Left.

Behavior:

  • If both fab and fa are Left, combines their errors using sg.Concat
  • If only fab is Left, returns Left with fab's error
  • If only fa is Left, returns Left with fa's error
  • If both are Right, applies the function and returns Right with the result

Type Parameters:

  • B: The result type after applying the function
  • E: The error type (must support the semigroup operation)
  • A: The input type to the function

Parameters:

  • sg: A semigroup that defines how to combine two error values

Returns:

  • A function that takes a wrapped function and a wrapped value, returning Either[E, B] with accumulated errors or the computed result

Example:

// Define a semigroup that concatenates error messages
errorSemigroup := semigroup.MakeSemigroup(func(e1, e2 string) string {
    return e1 + "; " + e2
})

// Create the validation applicative
applyV := either.MonadApV[int](errorSemigroup)

// Both are errors - errors get combined
fab := either.Left[func(int) int]("error1")
fa := either.Left[int]("error2")
result := applyV(fab, fa) // Left("error1; error2")

// One error - returns that error
fab2 := either.Right[string](N.Mul(2))
fa2 := either.Left[int]("validation failed")
result2 := applyV(fab2, fa2) // Left("validation failed")

// Both success - applies function
fab3 := either.Right[string](N.Mul(2))
fa3 := either.Right[string](21)
result3 := applyV(fab3, fa3) // Right(42)

func MonadFold

func MonadFold[E, A, B any](ma Either[E, A], onLeft func(e E) B, onRight func(a A) B) B

MonadFold extracts the value from an Either by providing handlers for both cases. This is the fundamental pattern matching operation for Either.

Example:

result := either.MonadFold(
    either.Right[error](42),
    func(err error) string { return "Error: " + err.Error() },
    func(n int) string { return fmt.Sprintf("Value: %d", n) },
) // "Value: 42"

func Pointed

func Pointed[E, A any]() pointed.Pointed[A, Either[E, A]]

Pointed implements the pointed functor operations for Either. A pointed functor provides the Of operation to lift a value into the Either context.

Example:

p := either.Pointed[error, int]()
result := p.Of(42) // Right(42)

func Reduce

func Reduce[E, A, B any](f func(B, A) B, initial B) func(Either[E, A]) B

Reduce folds an Either into a single value using a reducer function. Returns the initial value for Left, or applies the reducer to the Right value.

func Sequence

func Sequence[E, A, HKTA, HKTRA any](
	mof func(Either[E, A]) HKTRA,
	mmap func(Kleisli[E, A, A]) func(HKTA) HKTRA,
) func(Either[E, HKTA]) HKTRA

Sequence converts an Either of some higher kinded type into the higher kinded type of an Either. This is the identity version of Traverse - it doesn't transform the values, just swaps the type constructors.

Parameters:

  • mof: Lifts an Either into the target higher-kinded type
  • mmap: Maps over the target higher-kinded type

Example (conceptual - requires understanding of higher-kinded types):

// Sequence an Either[error, Option[int]] to Option[Either[error, int]]
result := either.Sequence[error, int, option.Option[int], option.Option[either.Either[error, int]]](
    option.Of[either.Either[error, int]],
    option.Map[int, either.Either[error, int]],
)(eitherOfOption)

func Sequence2

func Sequence2[E, T1, T2, R any](f func(T1, T2) Either[E, R]) func(Either[E, T1], Either[E, T2]) Either[E, R]

Sequence2 sequences two Either values using a combining function. Short-circuits on the first Left encountered.

func Sequence3

func Sequence3[E, T1, T2, T3, R any](f func(T1, T2, T3) Either[E, R]) func(Either[E, T1], Either[E, T2], Either[E, T3]) Either[E, R]

Sequence3 sequences three Either values using a combining function. Short-circuits on the first Left encountered.

func ToError

func ToError[A any](e Either[error, A]) error

ToError converts an Either[error, A] to an error, returning nil for Right values.

Example:

err := either.ToError(either.Left[int](errors.New("fail"))) // error
err := either.ToError(either.Right[error](42)) // nil

func ToSLogAttr

func ToSLogAttr[E, A any]() func(Either[E, A]) slog.Attr

ToSLogAttr converts an Either value to a structured logging attribute (slog.Attr).

This function creates a converter that transforms Either values into slog.Attr for use with Go's structured logging (log/slog). It maps:

  • Left values to an "error" attribute
  • Right values to a "value" attribute

This is particularly useful when integrating Either-based error handling with structured logging systems, allowing you to log both successful values and errors in a consistent, structured format.

Type Parameters:

  • E: The Left (error) type of the Either
  • A: The Right (success) type of the Either

Returns:

  • A function that converts Either[E, A] to slog.Attr

Example with Left (error):

converter := either.ToSLogAttr[error, int]()
leftValue := either.Left[int](errors.New("connection failed"))
attr := converter(leftValue)
// attr is: slog.Any("error", errors.New("connection failed"))

logger.LogAttrs(ctx, slog.LevelError, "Operation failed", attr)
// Logs: {"level":"error","msg":"Operation failed","error":"connection failed"}

Example with Right (success):

converter := either.ToSLogAttr[error, User]()
rightValue := either.Right[error](User{ID: 123, Name: "Alice"})
attr := converter(rightValue)
// attr is: slog.Any("value", User{ID: 123, Name: "Alice"})

logger.LogAttrs(ctx, slog.LevelInfo, "User fetched", attr)
// Logs: {"level":"info","msg":"User fetched","value":{"ID":123,"Name":"Alice"}}

Example in a pipeline with structured logging:

toAttr := either.ToSLogAttr[error, Data]()

result := F.Pipe2(
    fetchData(id),
    either.Map(processData),
    either.Map(validateData),
)

attr := toAttr(result)
logger.LogAttrs(ctx, slog.LevelInfo, "Data processing complete", attr)
// Logs success: {"level":"info","msg":"Data processing complete","value":{...}}
// Or error: {"level":"info","msg":"Data processing complete","error":"validation failed"}

Example with custom log levels based on Either:

toAttr := either.ToSLogAttr[error, Response]()
result := callAPI(endpoint)

level := either.Fold(
    func(error) slog.Level { return slog.LevelError },
    func(Response) slog.Level { return slog.LevelInfo },
)(result)

logger.LogAttrs(ctx, level, "API call completed", toAttr(result))

Use Cases:

  • Structured logging: Convert Either results to structured log attributes
  • Error tracking: Log errors with consistent "error" key in structured logs
  • Success monitoring: Log successful values with consistent "value" key
  • Observability: Integrate Either-based error handling with logging systems
  • Debugging: Inspect Either values in logs with proper structure
  • Metrics: Extract Either values for metrics collection in logging pipelines

Note: The returned slog.Attr uses "error" for Left values and "value" for Right values. These keys are consistent with common structured logging conventions.

func ToType

func ToType[A, E any](onError func(any) E) func(any) Either[E, A]

ToType attempts to convert an any value to a specific type, returning Either.

Example:

convert := either.ToType[int](func(v any) error {
    return fmt.Errorf("cannot convert %v to int", v)
})
result := convert(42) // Right(42)
result := convert("string") // Left(error)

func Traverse

func Traverse[A, E, B, HKTB, HKTRB any](
	mof func(Either[E, B]) HKTRB,
	mmap func(Kleisli[E, B, B]) func(HKTB) HKTRB,
) func(func(A) HKTB) func(Either[E, A]) HKTRB

Traverse converts an Either of some higher kinded type into the higher kinded type of an Either. This is a generic traversal operation that works with any applicative functor.

Parameters:

  • mof: Lifts an Either into the target higher-kinded type
  • mmap: Maps over the target higher-kinded type

Example (conceptual - requires understanding of higher-kinded types):

// Traverse an Either[error, Option[int]] to Option[Either[error, int]]
result := either.Traverse[int, error, int, option.Option[int], option.Option[either.Either[error, int]]](
    option.Of[either.Either[error, int]],
    option.Map[int, either.Either[error, int]],
)(f)(eitherOfOption)

func TraverseTuple1

func TraverseTuple1[F1 ~func(A1) Either[E, T1], E, A1, T1 any](f1 F1) func(T.Tuple1[A1]) Either[E, T.Tuple1[T1]]

TraverseTuple1 converts a [Tuple1] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple1]].

func TraverseTuple10

func TraverseTuple10[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], F4 ~func(A4) Either[E, T4], F5 ~func(A5) Either[E, T5], F6 ~func(A6) Either[E, T6], F7 ~func(A7) Either[E, T7], F8 ~func(A8) Either[E, T8], F9 ~func(A9) Either[E, T9], F10 ~func(A10) Either[E, T10], E, A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) func(T.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]) Either[E, T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]

TraverseTuple10 converts a [Tuple10] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple10]].

func TraverseTuple11

func TraverseTuple11[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], F4 ~func(A4) Either[E, T4], F5 ~func(A5) Either[E, T5], F6 ~func(A6) Either[E, T6], F7 ~func(A7) Either[E, T7], F8 ~func(A8) Either[E, T8], F9 ~func(A9) Either[E, T9], F10 ~func(A10) Either[E, T10], F11 ~func(A11) Either[E, T11], E, A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10, A11, T11 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11) func(T.Tuple11[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11]) Either[E, T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]]

TraverseTuple11 converts a [Tuple11] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple11]].

func TraverseTuple12

func TraverseTuple12[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], F4 ~func(A4) Either[E, T4], F5 ~func(A5) Either[E, T5], F6 ~func(A6) Either[E, T6], F7 ~func(A7) Either[E, T7], F8 ~func(A8) Either[E, T8], F9 ~func(A9) Either[E, T9], F10 ~func(A10) Either[E, T10], F11 ~func(A11) Either[E, T11], F12 ~func(A12) Either[E, T12], E, A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10, A11, T11, A12, T12 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12) func(T.Tuple12[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12]) Either[E, T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]]

TraverseTuple12 converts a [Tuple12] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple12]].

func TraverseTuple13

func TraverseTuple13[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], F4 ~func(A4) Either[E, T4], F5 ~func(A5) Either[E, T5], F6 ~func(A6) Either[E, T6], F7 ~func(A7) Either[E, T7], F8 ~func(A8) Either[E, T8], F9 ~func(A9) Either[E, T9], F10 ~func(A10) Either[E, T10], F11 ~func(A11) Either[E, T11], F12 ~func(A12) Either[E, T12], F13 ~func(A13) Either[E, T13], E, A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10, A11, T11, A12, T12, A13, T13 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13) func(T.Tuple13[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13]) Either[E, T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]]

TraverseTuple13 converts a [Tuple13] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple13]].

func TraverseTuple14

func TraverseTuple14[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], F4 ~func(A4) Either[E, T4], F5 ~func(A5) Either[E, T5], F6 ~func(A6) Either[E, T6], F7 ~func(A7) Either[E, T7], F8 ~func(A8) Either[E, T8], F9 ~func(A9) Either[E, T9], F10 ~func(A10) Either[E, T10], F11 ~func(A11) Either[E, T11], F12 ~func(A12) Either[E, T12], F13 ~func(A13) Either[E, T13], F14 ~func(A14) Either[E, T14], E, A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10, A11, T11, A12, T12, A13, T13, A14, T14 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14) func(T.Tuple14[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14]) Either[E, T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]]

TraverseTuple14 converts a [Tuple14] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple14]].

func TraverseTuple15

func TraverseTuple15[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], F4 ~func(A4) Either[E, T4], F5 ~func(A5) Either[E, T5], F6 ~func(A6) Either[E, T6], F7 ~func(A7) Either[E, T7], F8 ~func(A8) Either[E, T8], F9 ~func(A9) Either[E, T9], F10 ~func(A10) Either[E, T10], F11 ~func(A11) Either[E, T11], F12 ~func(A12) Either[E, T12], F13 ~func(A13) Either[E, T13], F14 ~func(A14) Either[E, T14], F15 ~func(A15) Either[E, T15], E, A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10, A11, T11, A12, T12, A13, T13, A14, T14, A15, T15 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15) func(T.Tuple15[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15]) Either[E, T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]]

TraverseTuple15 converts a [Tuple15] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple15]].

func TraverseTuple2

func TraverseTuple2[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], E, A1, T1, A2, T2 any](f1 F1, f2 F2) func(T.Tuple2[A1, A2]) Either[E, T.Tuple2[T1, T2]]

TraverseTuple2 converts a [Tuple2] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple2]].

func TraverseTuple3

func TraverseTuple3[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], E, A1, T1, A2, T2, A3, T3 any](f1 F1, f2 F2, f3 F3) func(T.Tuple3[A1, A2, A3]) Either[E, T.Tuple3[T1, T2, T3]]

TraverseTuple3 converts a [Tuple3] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple3]].

func TraverseTuple4

func TraverseTuple4[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], F4 ~func(A4) Either[E, T4], E, A1, T1, A2, T2, A3, T3, A4, T4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(T.Tuple4[A1, A2, A3, A4]) Either[E, T.Tuple4[T1, T2, T3, T4]]

TraverseTuple4 converts a [Tuple4] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple4]].

func TraverseTuple5

func TraverseTuple5[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], F4 ~func(A4) Either[E, T4], F5 ~func(A5) Either[E, T5], E, A1, T1, A2, T2, A3, T3, A4, T4, A5, T5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(T.Tuple5[A1, A2, A3, A4, A5]) Either[E, T.Tuple5[T1, T2, T3, T4, T5]]

TraverseTuple5 converts a [Tuple5] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple5]].

func TraverseTuple6

func TraverseTuple6[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], F4 ~func(A4) Either[E, T4], F5 ~func(A5) Either[E, T5], F6 ~func(A6) Either[E, T6], E, A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(T.Tuple6[A1, A2, A3, A4, A5, A6]) Either[E, T.Tuple6[T1, T2, T3, T4, T5, T6]]

TraverseTuple6 converts a [Tuple6] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple6]].

func TraverseTuple7

func TraverseTuple7[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], F4 ~func(A4) Either[E, T4], F5 ~func(A5) Either[E, T5], F6 ~func(A6) Either[E, T6], F7 ~func(A7) Either[E, T7], E, A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) func(T.Tuple7[A1, A2, A3, A4, A5, A6, A7]) Either[E, T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]

TraverseTuple7 converts a [Tuple7] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple7]].

func TraverseTuple8

func TraverseTuple8[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], F4 ~func(A4) Either[E, T4], F5 ~func(A5) Either[E, T5], F6 ~func(A6) Either[E, T6], F7 ~func(A7) Either[E, T7], F8 ~func(A8) Either[E, T8], E, A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) func(T.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]) Either[E, T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]

TraverseTuple8 converts a [Tuple8] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple8]].

func TraverseTuple9

func TraverseTuple9[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~func(A3) Either[E, T3], F4 ~func(A4) Either[E, T4], F5 ~func(A5) Either[E, T5], F6 ~func(A6) Either[E, T6], F7 ~func(A7) Either[E, T7], F8 ~func(A8) Either[E, T8], F9 ~func(A9) Either[E, T9], E, A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) func(T.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]) Either[E, T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]

TraverseTuple9 converts a [Tuple9] of [A] via transformation functions transforming [A] to [Either[E, A]] into a [Either[E, Tuple9]].

func Uncurry0

func Uncurry0[R any](f func() Either[error, R]) func() (R, error)

Uncurry0 converts a function returning Either[error, R] back to Go's (R, error) style.

Example:

curried := func() either.Either[error, string] { return either.Right[error]("value") }
uncurried := either.Uncurry0(curried)
result, err := uncurried() // "value", nil

func Uncurry1

func Uncurry1[T1, R any](f func(T1) Either[error, R]) func(T1) (R, error)

Uncurry1 converts a function returning Either[error, R] back to Go's (R, error) style.

Example:

curried := func(x int) either.Either[error, string] { return either.Right[error](strconv.Itoa(x)) }
uncurried := either.Uncurry1(curried)
result, err := uncurried(42) // "42", nil

func Uncurry2

func Uncurry2[T1, T2, R any](f func(T1) func(T2) Either[error, R]) func(T1, T2) (R, error)

Uncurry2 converts a curried function returning Either[error, R] back to Go's (R, error) style.

func Uncurry3

func Uncurry3[T1, T2, T3, R any](f func(T1) func(T2) func(T3) Either[error, R]) func(T1, T2, T3) (R, error)

Uncurry3 converts a curried function returning Either[error, R] back to Go's (R, error) style.

func Uncurry4

func Uncurry4[T1, T2, T3, T4, R any](f func(T1) func(T2) func(T3) func(T4) Either[error, R]) func(T1, T2, T3, T4) (R, error)

Uncurry4 converts a curried function returning Either[error, R] back to Go's (R, error) style.

func Uneitherize0

func Uneitherize0[F ~func() Either[error, R], R any](f F) func() (R, error)

Uneitherize0 converts a function with 0 parameters returning an Either into a function with 0 parameters returning a tuple The inverse function is Eitherize0

func Uneitherize1

func Uneitherize1[F ~func(T0) Either[error, R], T0, R any](f F) func(T0) (R, error)

Uneitherize1 converts a function with 1 parameters returning an Either into a function with 1 parameters returning a tuple The inverse function is Eitherize1

func Uneitherize10

func Uneitherize10[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error)

Uneitherize10 converts a function with 10 parameters returning an Either into a function with 10 parameters returning a tuple The inverse function is Eitherize10

func Uneitherize11

func Uneitherize11[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) (R, error)

Uneitherize11 converts a function with 11 parameters returning an Either into a function with 11 parameters returning a tuple The inverse function is Eitherize11

func Uneitherize12

func Uneitherize12[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) (R, error)

Uneitherize12 converts a function with 12 parameters returning an Either into a function with 12 parameters returning a tuple The inverse function is Eitherize12

func Uneitherize13

func Uneitherize13[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) (R, error)

Uneitherize13 converts a function with 13 parameters returning an Either into a function with 13 parameters returning a tuple The inverse function is Eitherize13

func Uneitherize14

func Uneitherize14[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) (R, error)

Uneitherize14 converts a function with 14 parameters returning an Either into a function with 14 parameters returning a tuple The inverse function is Eitherize14

func Uneitherize15

func Uneitherize15[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) (R, error)

Uneitherize15 converts a function with 15 parameters returning an Either into a function with 15 parameters returning a tuple The inverse function is Eitherize15

func Uneitherize2

func Uneitherize2[F ~func(T0, T1) Either[error, R], T0, T1, R any](f F) func(T0, T1) (R, error)

Uneitherize2 converts a function with 2 parameters returning an Either into a function with 2 parameters returning a tuple The inverse function is Eitherize2

func Uneitherize3

func Uneitherize3[F ~func(T0, T1, T2) Either[error, R], T0, T1, T2, R any](f F) func(T0, T1, T2) (R, error)

Uneitherize3 converts a function with 3 parameters returning an Either into a function with 3 parameters returning a tuple The inverse function is Eitherize3

func Uneitherize4

func Uneitherize4[F ~func(T0, T1, T2, T3) Either[error, R], T0, T1, T2, T3, R any](f F) func(T0, T1, T2, T3) (R, error)

Uneitherize4 converts a function with 4 parameters returning an Either into a function with 4 parameters returning a tuple The inverse function is Eitherize4

func Uneitherize5

func Uneitherize5[F ~func(T0, T1, T2, T3, T4) Either[error, R], T0, T1, T2, T3, T4, R any](f F) func(T0, T1, T2, T3, T4) (R, error)

Uneitherize5 converts a function with 5 parameters returning an Either into a function with 5 parameters returning a tuple The inverse function is Eitherize5

func Uneitherize6

func Uneitherize6[F ~func(T0, T1, T2, T3, T4, T5) Either[error, R], T0, T1, T2, T3, T4, T5, R any](f F) func(T0, T1, T2, T3, T4, T5) (R, error)

Uneitherize6 converts a function with 6 parameters returning an Either into a function with 6 parameters returning a tuple The inverse function is Eitherize6

func Uneitherize7

func Uneitherize7[F ~func(T0, T1, T2, T3, T4, T5, T6) Either[error, R], T0, T1, T2, T3, T4, T5, T6, R any](f F) func(T0, T1, T2, T3, T4, T5, T6) (R, error)

Uneitherize7 converts a function with 7 parameters returning an Either into a function with 7 parameters returning a tuple The inverse function is Eitherize7

func Uneitherize8

func Uneitherize8[F ~func(T0, T1, T2, T3, T4, T5, T6, T7) Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7) (R, error)

Uneitherize8 converts a function with 8 parameters returning an Either into a function with 8 parameters returning a tuple The inverse function is Eitherize8

func Uneitherize9

func Uneitherize9[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8) Either[error, R], T0, T1, T2, T3, T4, T5, T6, T7, T8, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error)

Uneitherize9 converts a function with 9 parameters returning an Either into a function with 9 parameters returning a tuple The inverse function is Eitherize9

func Unvariadic0

func Unvariadic0[V, R any](f func(...V) (R, error)) func([]V) Either[error, R]

Unvariadic0 converts a variadic function returning (R, error) into a function taking a slice and returning Either.

func Unvariadic1

func Unvariadic1[T1, V, R any](f func(T1, ...V) (R, error)) func(T1, []V) Either[error, R]

Unvariadic1 converts a variadic function with 1 fixed parameter into a function taking a slice and returning Either.

func Unvariadic2

func Unvariadic2[T1, T2, V, R any](f func(T1, T2, ...V) (R, error)) func(T1, T2, []V) Either[error, R]

Unvariadic2 converts a variadic function with 2 fixed parameters into a function taking a slice and returning Either.

func Unvariadic3

func Unvariadic3[T1, T2, T3, V, R any](f func(T1, T2, T3, ...V) (R, error)) func(T1, T2, T3, []V) Either[error, R]

Unvariadic3 converts a variadic function with 3 fixed parameters into a function taking a slice and returning Either.

func Unvariadic4

func Unvariadic4[T1, T2, T3, T4, V, R any](f func(T1, T2, T3, T4, ...V) (R, error)) func(T1, T2, T3, T4, []V) Either[error, R]

Unvariadic4 converts a variadic function with 4 fixed parameters into a function taking a slice and returning Either.

func Unwrap

func Unwrap[E, A any](ma Either[E, A]) (A, E)

Unwrap converts an Either into the idiomatic Go tuple (value, error). For Right values, returns (value, zero-error). For Left values, returns (zero-value, error).

Example:

val, err := either.Unwrap(either.Right[error](42)) // 42, nil
val, err := either.Unwrap(either.Left[int](errors.New("fail"))) // 0, error

func UnwrapError

func UnwrapError[A any](ma Either[error, A]) (A, error)

UnwrapError converts an Either[error, A] into the idiomatic Go tuple (A, error).

Example:

val, err := either.UnwrapError(either.Right[error](42)) // 42, nil
val, err := either.UnwrapError(either.Left[int](errors.New("fail"))) // zero, error

func Variadic0

func Variadic0[V, R any](f func([]V) (R, error)) func(...V) Either[error, R]

Variadic0 converts a function taking a slice and returning (R, error) into a variadic function returning Either.

Example:

sum := func(nums []int) (int, error) {
    total := 0
    for _, n := range nums { total += n }
    return total, nil
}
variadicSum := either.Variadic0(sum)
result := variadicSum(1, 2, 3) // Right(6)

func Variadic1

func Variadic1[T1, V, R any](f func(T1, []V) (R, error)) func(T1, ...V) Either[error, R]

Variadic1 converts a function with 1 fixed parameter and a slice into a variadic function returning Either.

func Variadic2

func Variadic2[T1, T2, V, R any](f func(T1, T2, []V) (R, error)) func(T1, T2, ...V) Either[error, R]

Variadic2 converts a function with 2 fixed parameters and a slice into a variadic function returning Either.

func Variadic3

func Variadic3[T1, T2, T3, V, R any](f func(T1, T2, T3, []V) (R, error)) func(T1, T2, T3, ...V) Either[error, R]

Variadic3 converts a function with 3 fixed parameters and a slice into a variadic function returning Either.

func Variadic4

func Variadic4[T1, T2, T3, T4, V, R any](f func(T1, T2, T3, T4, []V) (R, error)) func(T1, T2, T3, T4, ...V) Either[error, R]

Variadic4 converts a function with 4 fixed parameters and a slice into a variadic function returning Either.

Types

type Either

type Either[E, A any] struct {
	// contains filtered or unexported fields
}

Either defines a data structure that logically holds either an E or an A. The flag discriminates the cases

Example (Creation)
// Build an Either
leftValue := Left[string](fmt.Errorf("some error"))
rightValue := Right[error]("value")

// Build from a value
fromNillable := FromNillable[string](fmt.Errorf("value was nil"))
leftFromNil := fromNillable(nil)
value := "value"
rightFromPointer := fromNillable(&value)

// some predicate
isEven := func(num int) bool {
	return num%2 == 0
}
fromEven := FromPredicate(isEven, errors.OnSome[int]("%d is an odd number"))
leftFromPred := fromEven(3)
rightFromPred := fromEven(4)

fmt.Println(leftValue)
fmt.Println(rightValue)
fmt.Println(leftFromNil)
fmt.Println(IsRight(rightFromPointer))
fmt.Println(leftFromPred)
fmt.Println(rightFromPred)
Output:

Left[*errors.errorString](some error)
Right[string](value)
Left[*errors.errorString](value was nil)
true
Left[*errors.errorString](3 is an odd number)
Right[int](4)
Example (Extraction)
leftValue := Left[int](fmt.Errorf("Division by Zero!"))
rightValue := Right[error](10)

// Convert Either[E, A] to A with a default value
leftWithDefault := GetOrElse(F.Constant1[error](0))(leftValue)   // 0
rightWithDefault := GetOrElse(F.Constant1[error](0))(rightValue) // 10

// Apply a different function on Left(...)/Right(...)
doubleOrZero := Fold(F.Constant1[error](0), N.Mul(2)) // func(Either[error, int]) int
doubleFromLeft := doubleOrZero(leftValue)             // 0
doubleFromRight := doubleOrZero(rightValue)           // 20

// Pro-tip: Fold is short for the following:
doubleOrZeroBis := F.Flow2(
	Map[error](N.Mul(2)),
	GetOrElse(F.Constant1[error](0)),
)
doubleFromLeftBis := doubleOrZeroBis(leftValue)   // 0
doubleFromRightBis := doubleOrZeroBis(rightValue) // 20

fmt.Println(leftValue)
fmt.Println(rightValue)
fmt.Println(leftWithDefault)
fmt.Println(rightWithDefault)
fmt.Println(doubleFromLeft)
fmt.Println(doubleFromRight)
fmt.Println(doubleFromLeftBis)
fmt.Println(doubleFromRightBis)
Output:

Left[*errors.errorString](Division by Zero!)
Right[int](10)
0
10
0
20
0
20
Example (Formatting_comparison)

ExampleEither_formatting_comparison demonstrates different formatting options.

package main

import (
	"fmt"

	E "github.com/IBM/fp-go/v2/either"
)

func main() {
	type User struct {
		ID   int
		Name string
	}

	user := User{ID: 123, Name: "Alice"}
	result := E.Right[error](user)

	fmt.Printf("String():   %s\n", result.String())
	fmt.Printf("GoString(): %s\n", result.GoString())
	fmt.Printf("%%v:         %v\n", result)
	fmt.Printf("%%#v:        %#v\n", result)

}
Output:

String():   Right[either_test.User]({123 Alice})
GoString(): either.Right[error](either_test.User{ID:123, Name:"Alice"})
%v:         Right[either_test.User]({123 Alice})
%#v:        either.Right[error](either_test.User{ID:123, Name:"Alice"})

func Do

func Do[E, S any](
	empty S,
) Either[E, 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 computations.

Example:

type State struct { x, y int }
result := either.Do[error](State{})

func Flatten

func Flatten[E, A any](mma Either[E, Either[E, A]]) Either[E, A]

Flatten removes one level of nesting from a nested Either.

Example:

nested := either.Right[error](either.Right[error](42))
result := either.Flatten(nested) // Right(42)

func FromIO

func FromIO[E any, IO ~func() A, A any](f IO) Either[E, A]

FromIO executes an IO operation and wraps the result in a Right value. This is useful for lifting pure IO operations into the Either context.

Example:

getValue := func() int { return 42 }
result := either.FromIO[error](getValue) // Right(42)

go: inline

func Left

func Left[A, E any](value E) Either[E, A]

Left creates a new Either representing a Left (error/failure) value. By convention, Left represents the error case.

Example:

result := either.Left[int](errors.New("something went wrong"))

func Memoize

func Memoize[E, A any](val Either[E, A]) Either[E, A]

Memoize returns the Either unchanged (Either values are already memoized).

func MonadAlt

func MonadAlt[E, A any](fa Either[E, A], that Lazy[Either[E, A]]) Either[E, A]

MonadAlt provides an alternative Either if the first is Left. This is the monadic version of Alt.

func MonadAp

func MonadAp[B, E, A any](fab Either[E, func(a A) B], fa Either[E, A]) Either[E, B]

MonadAp applies a function wrapped in Either to a value wrapped in Either. If either the function or the value is Left, returns Left. This is the applicative apply operation.

Example:

fab := either.Right[error](N.Mul(2))
fa := either.Right[error](21)
result := either.MonadAp(fab, fa) // Right(42)

func MonadBiMap

func MonadBiMap[E1, E2, A, B any](fa Either[E1, A], f func(E1) E2, g func(a A) B) Either[E2, B]

MonadBiMap applies two functions: one to transform a Left value, another to transform a Right value. This allows transforming both channels of the Either simultaneously.

Example:

result := either.MonadBiMap(
    either.Left[int](errors.New("error")),
    error.Error,
    func(n int) string { return fmt.Sprint(n) },
) // Left("error")

func MonadChain

func MonadChain[E, A, B any](fa Either[E, A], f Kleisli[E, A, B]) Either[E, B]

MonadChain sequences two computations, where the second depends on the result of the first. If the first Either is Left, returns Left without executing the second computation. This is the monadic bind operation (also known as flatMap).

Example:

result := either.MonadChain(
    either.Right[error](21),
    func(x int) either.Either[error, int] {
        return either.Right[error](x * 2)
    },
) // Right(42)

func MonadChainFirst

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

MonadChainFirst executes a side-effect computation but returns the original value. Useful for performing actions (like logging) without changing the value.

Example:

result := either.MonadChainFirst(
    either.Right[error](42),
    func(x int) either.Either[error, string] {
        fmt.Println(x) // side effect
        return either.Right[error]("logged")
    },
) // Right(42) - original value preserved

func MonadChainOptionK

func MonadChainOptionK[A, B, E any](onNone func() E, ma Either[E, A], f func(A) Option[B]) Either[E, B]

MonadChainOptionK chains a function that returns an Option, converting None to Left.

Example:

result := either.MonadChainOptionK(
    func() error { return errors.New("not found") },
    either.Right[error](42),
    func(x int) option.Option[string] {
        if x > 0 { return option.Some("positive") }
        return option.None[string]()
    },
) // Right("positive")

func MonadChainTo

func MonadChainTo[A, E, B any](_ Either[E, A], mb Either[E, B]) Either[E, B]

MonadChainTo ignores the first Either and returns the second. Useful for sequencing operations where you don't need the first result.

func MonadFlap

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

MonadFlap applies a value to a function wrapped in Either. This is the reverse of MonadAp.

func MonadMap

func MonadMap[E, A, B any](fa Either[E, A], f func(a A) B) Either[E, B]

MonadMap transforms the Right value using the provided function. If the Either is Left, returns Left unchanged. This is the functor map operation.

Example:

result := either.MonadMap(
    either.Right[error](21),
    N.Mul(2),
) // Right(42)

func MonadMapLeft

func MonadMapLeft[E1, A, E2 any](fa Either[E1, A], f func(E1) E2) Either[E2, A]

MonadMapLeft applies a transformation function to the Left (error) value. If the Either is Right, returns Right unchanged.

Example:

result := either.MonadMapLeft(
    either.Left[int](errors.New("error")),
    error.Error,
) // Left("error")

func MonadMapTo

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

MonadMapTo replaces the Right value with a constant value. If the Either is Left, returns Left unchanged.

Example:

result := either.MonadMapTo(either.Right[error](21), "success") // Right("success")

func MonadSequence2

func MonadSequence2[E, T1, T2, R any](e1 Either[E, T1], e2 Either[E, T2], f func(T1, T2) Either[E, R]) Either[E, R]

MonadSequence2 sequences two Either values using a combining function. Short-circuits on the first Left encountered.

func MonadSequence3

func MonadSequence3[E, T1, T2, T3, R any](e1 Either[E, T1], e2 Either[E, T2], e3 Either[E, T3], f func(T1, T2, T3) Either[E, R]) Either[E, R]

MonadSequence3 sequences three Either values using a combining function. Short-circuits on the first Left encountered.

func Of

func Of[E, A any](value A) Either[E, A]

Of constructs a Right value containing the given value. This is the monadic return/pure operation for Either. Equivalent to Right.

Example:

result := either.Of[error](42) // Right(42)
func Right[E, A any](value A) Either[E, A]

Right creates a new Either representing a Right (success) value. By convention, Right represents the success case.

Example:

result := either.Right[error](42)

func SequenceArray

func SequenceArray[E, A any](ma []Either[E, A]) Either[E, []A]

SequenceArray converts a homogeneous sequence of Either into an Either of sequence. If any element is Left, returns that Left (short-circuits). Otherwise, returns Right containing all the Right values.

Example:

eithers := []either.Either[error, int]{
    either.Right[error](1),
    either.Right[error](2),
    either.Right[error](3),
}
result := either.SequenceArray(eithers)
// result is Right([]int{1, 2, 3})

func SequenceArrayG

func SequenceArrayG[GA ~[]A, GOA ~[]Either[E, A], E, A any](ma GOA) Either[E, GA]

func SequenceRecord

func SequenceRecord[K comparable, E, A any](ma map[K]Either[E, A]) Either[E, map[K]A]

SequenceRecord converts a map of Either values into an Either of a map. If any value is Left, returns that Left (short-circuits). Otherwise, returns Right containing a map of all the Right values.

Example:

eithers := map[string]either.Either[error, int]{
    "a": either.Right[error](1),
    "b": either.Right[error](2),
}
result := either.SequenceRecord(eithers)
// result is Right(map[string]int{"a": 1, "b": 2})

func SequenceRecordG

func SequenceRecordG[GA ~map[K]A, GOA ~map[K]Either[E, A], K comparable, E, A any](ma GOA) Either[E, GA]

func SequenceT1

func SequenceT1[E, T1 any](t1 Either[E, T1]) Either[E, T.Tuple1[T1]]

SequenceT1 converts 1 parameters of [Either[E, T]] into a [Either[E, Tuple1]].

func SequenceT10

func SequenceT10[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3], t4 Either[E, T4], t5 Either[E, T5], t6 Either[E, T6], t7 Either[E, T7], t8 Either[E, T8], t9 Either[E, T9], t10 Either[E, T10]) Either[E, T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]

SequenceT10 converts 10 parameters of [Either[E, T]] into a [Either[E, Tuple10]].

func SequenceT11

func SequenceT11[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3], t4 Either[E, T4], t5 Either[E, T5], t6 Either[E, T6], t7 Either[E, T7], t8 Either[E, T8], t9 Either[E, T9], t10 Either[E, T10], t11 Either[E, T11]) Either[E, T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]]

SequenceT11 converts 11 parameters of [Either[E, T]] into a [Either[E, Tuple11]].

func SequenceT12

func SequenceT12[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3], t4 Either[E, T4], t5 Either[E, T5], t6 Either[E, T6], t7 Either[E, T7], t8 Either[E, T8], t9 Either[E, T9], t10 Either[E, T10], t11 Either[E, T11], t12 Either[E, T12]) Either[E, T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]]

SequenceT12 converts 12 parameters of [Either[E, T]] into a [Either[E, Tuple12]].

func SequenceT13

func SequenceT13[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3], t4 Either[E, T4], t5 Either[E, T5], t6 Either[E, T6], t7 Either[E, T7], t8 Either[E, T8], t9 Either[E, T9], t10 Either[E, T10], t11 Either[E, T11], t12 Either[E, T12], t13 Either[E, T13]) Either[E, T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]]

SequenceT13 converts 13 parameters of [Either[E, T]] into a [Either[E, Tuple13]].

func SequenceT14

func SequenceT14[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3], t4 Either[E, T4], t5 Either[E, T5], t6 Either[E, T6], t7 Either[E, T7], t8 Either[E, T8], t9 Either[E, T9], t10 Either[E, T10], t11 Either[E, T11], t12 Either[E, T12], t13 Either[E, T13], t14 Either[E, T14]) Either[E, T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]]

SequenceT14 converts 14 parameters of [Either[E, T]] into a [Either[E, Tuple14]].

func SequenceT15

func SequenceT15[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3], t4 Either[E, T4], t5 Either[E, T5], t6 Either[E, T6], t7 Either[E, T7], t8 Either[E, T8], t9 Either[E, T9], t10 Either[E, T10], t11 Either[E, T11], t12 Either[E, T12], t13 Either[E, T13], t14 Either[E, T14], t15 Either[E, T15]) Either[E, T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]]

SequenceT15 converts 15 parameters of [Either[E, T]] into a [Either[E, Tuple15]].

func SequenceT2

func SequenceT2[E, T1, T2 any](t1 Either[E, T1], t2 Either[E, T2]) Either[E, T.Tuple2[T1, T2]]

SequenceT2 converts 2 parameters of [Either[E, T]] into a [Either[E, Tuple2]].

func SequenceT3

func SequenceT3[E, T1, T2, T3 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3]) Either[E, T.Tuple3[T1, T2, T3]]

SequenceT3 converts 3 parameters of [Either[E, T]] into a [Either[E, Tuple3]].

func SequenceT4

func SequenceT4[E, T1, T2, T3, T4 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3], t4 Either[E, T4]) Either[E, T.Tuple4[T1, T2, T3, T4]]

SequenceT4 converts 4 parameters of [Either[E, T]] into a [Either[E, Tuple4]].

func SequenceT5

func SequenceT5[E, T1, T2, T3, T4, T5 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3], t4 Either[E, T4], t5 Either[E, T5]) Either[E, T.Tuple5[T1, T2, T3, T4, T5]]

SequenceT5 converts 5 parameters of [Either[E, T]] into a [Either[E, Tuple5]].

func SequenceT6

func SequenceT6[E, T1, T2, T3, T4, T5, T6 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3], t4 Either[E, T4], t5 Either[E, T5], t6 Either[E, T6]) Either[E, T.Tuple6[T1, T2, T3, T4, T5, T6]]

SequenceT6 converts 6 parameters of [Either[E, T]] into a [Either[E, Tuple6]].

func SequenceT7

func SequenceT7[E, T1, T2, T3, T4, T5, T6, T7 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3], t4 Either[E, T4], t5 Either[E, T5], t6 Either[E, T6], t7 Either[E, T7]) Either[E, T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]

SequenceT7 converts 7 parameters of [Either[E, T]] into a [Either[E, Tuple7]].

func SequenceT8

func SequenceT8[E, T1, T2, T3, T4, T5, T6, T7, T8 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3], t4 Either[E, T4], t5 Either[E, T5], t6 Either[E, T6], t7 Either[E, T7], t8 Either[E, T8]) Either[E, T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]

SequenceT8 converts 8 parameters of [Either[E, T]] into a [Either[E, Tuple8]].

func SequenceT9

func SequenceT9[E, T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t1 Either[E, T1], t2 Either[E, T2], t3 Either[E, T3], t4 Either[E, T4], t5 Either[E, T5], t6 Either[E, T6], t7 Either[E, T7], t8 Either[E, T8], t9 Either[E, T9]) Either[E, T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]

SequenceT9 converts 9 parameters of [Either[E, T]] into a [Either[E, Tuple9]].

func SequenceTuple1

func SequenceTuple1[E, T1 any](t T.Tuple1[Either[E, T1]]) Either[E, T.Tuple1[T1]]

SequenceTuple1 converts a [Tuple1] of [Either[E, T]] into an [Either[E, Tuple1]].

func SequenceTuple10

func SequenceTuple10[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t T.Tuple10[Either[E, T1], Either[E, T2], Either[E, T3], Either[E, T4], Either[E, T5], Either[E, T6], Either[E, T7], Either[E, T8], Either[E, T9], Either[E, T10]]) Either[E, T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]

SequenceTuple10 converts a [Tuple10] of [Either[E, T]] into an [Either[E, Tuple10]].

func SequenceTuple11

func SequenceTuple11[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any](t T.Tuple11[Either[E, T1], Either[E, T2], Either[E, T3], Either[E, T4], Either[E, T5], Either[E, T6], Either[E, T7], Either[E, T8], Either[E, T9], Either[E, T10], Either[E, T11]]) Either[E, T.Tuple11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]]

SequenceTuple11 converts a [Tuple11] of [Either[E, T]] into an [Either[E, Tuple11]].

func SequenceTuple12

func SequenceTuple12[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any](t T.Tuple12[Either[E, T1], Either[E, T2], Either[E, T3], Either[E, T4], Either[E, T5], Either[E, T6], Either[E, T7], Either[E, T8], Either[E, T9], Either[E, T10], Either[E, T11], Either[E, T12]]) Either[E, T.Tuple12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]]

SequenceTuple12 converts a [Tuple12] of [Either[E, T]] into an [Either[E, Tuple12]].

func SequenceTuple13

func SequenceTuple13[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any](t T.Tuple13[Either[E, T1], Either[E, T2], Either[E, T3], Either[E, T4], Either[E, T5], Either[E, T6], Either[E, T7], Either[E, T8], Either[E, T9], Either[E, T10], Either[E, T11], Either[E, T12], Either[E, T13]]) Either[E, T.Tuple13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]]

SequenceTuple13 converts a [Tuple13] of [Either[E, T]] into an [Either[E, Tuple13]].

func SequenceTuple14

func SequenceTuple14[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any](t T.Tuple14[Either[E, T1], Either[E, T2], Either[E, T3], Either[E, T4], Either[E, T5], Either[E, T6], Either[E, T7], Either[E, T8], Either[E, T9], Either[E, T10], Either[E, T11], Either[E, T12], Either[E, T13], Either[E, T14]]) Either[E, T.Tuple14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]]

SequenceTuple14 converts a [Tuple14] of [Either[E, T]] into an [Either[E, Tuple14]].

func SequenceTuple15

func SequenceTuple15[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 any](t T.Tuple15[Either[E, T1], Either[E, T2], Either[E, T3], Either[E, T4], Either[E, T5], Either[E, T6], Either[E, T7], Either[E, T8], Either[E, T9], Either[E, T10], Either[E, T11], Either[E, T12], Either[E, T13], Either[E, T14], Either[E, T15]]) Either[E, T.Tuple15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]]

SequenceTuple15 converts a [Tuple15] of [Either[E, T]] into an [Either[E, Tuple15]].

func SequenceTuple2

func SequenceTuple2[E, T1, T2 any](t T.Tuple2[Either[E, T1], Either[E, T2]]) Either[E, T.Tuple2[T1, T2]]

SequenceTuple2 converts a [Tuple2] of [Either[E, T]] into an [Either[E, Tuple2]].

func SequenceTuple3

func SequenceTuple3[E, T1, T2, T3 any](t T.Tuple3[Either[E, T1], Either[E, T2], Either[E, T3]]) Either[E, T.Tuple3[T1, T2, T3]]

SequenceTuple3 converts a [Tuple3] of [Either[E, T]] into an [Either[E, Tuple3]].

func SequenceTuple4

func SequenceTuple4[E, T1, T2, T3, T4 any](t T.Tuple4[Either[E, T1], Either[E, T2], Either[E, T3], Either[E, T4]]) Either[E, T.Tuple4[T1, T2, T3, T4]]

SequenceTuple4 converts a [Tuple4] of [Either[E, T]] into an [Either[E, Tuple4]].

func SequenceTuple5

func SequenceTuple5[E, T1, T2, T3, T4, T5 any](t T.Tuple5[Either[E, T1], Either[E, T2], Either[E, T3], Either[E, T4], Either[E, T5]]) Either[E, T.Tuple5[T1, T2, T3, T4, T5]]

SequenceTuple5 converts a [Tuple5] of [Either[E, T]] into an [Either[E, Tuple5]].

func SequenceTuple6

func SequenceTuple6[E, T1, T2, T3, T4, T5, T6 any](t T.Tuple6[Either[E, T1], Either[E, T2], Either[E, T3], Either[E, T4], Either[E, T5], Either[E, T6]]) Either[E, T.Tuple6[T1, T2, T3, T4, T5, T6]]

SequenceTuple6 converts a [Tuple6] of [Either[E, T]] into an [Either[E, Tuple6]].

func SequenceTuple7

func SequenceTuple7[E, T1, T2, T3, T4, T5, T6, T7 any](t T.Tuple7[Either[E, T1], Either[E, T2], Either[E, T3], Either[E, T4], Either[E, T5], Either[E, T6], Either[E, T7]]) Either[E, T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]

SequenceTuple7 converts a [Tuple7] of [Either[E, T]] into an [Either[E, Tuple7]].

func SequenceTuple8

func SequenceTuple8[E, T1, T2, T3, T4, T5, T6, T7, T8 any](t T.Tuple8[Either[E, T1], Either[E, T2], Either[E, T3], Either[E, T4], Either[E, T5], Either[E, T6], Either[E, T7], Either[E, T8]]) Either[E, T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]

SequenceTuple8 converts a [Tuple8] of [Either[E, T]] into an [Either[E, Tuple8]].

func SequenceTuple9

func SequenceTuple9[E, T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t T.Tuple9[Either[E, T1], Either[E, T2], Either[E, T3], Either[E, T4], Either[E, T5], Either[E, T6], Either[E, T7], Either[E, T8], Either[E, T9]]) Either[E, T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]

SequenceTuple9 converts a [Tuple9] of [Either[E, T]] into an [Either[E, Tuple9]].

func Swap

func Swap[E, A any](val Either[E, A]) Either[A, E]

Swap exchanges the Left and Right type parameters.

Example:

result := either.Swap(either.Right[error](42)) // Left(42)
result := either.Swap(either.Left[int](errors.New("err"))) // Right(error)

func TryCatch

func TryCatch[FE func(error) E, E, A any](val A, err error, onThrow FE) Either[E, A]

TryCatch converts a (value, error) tuple into an Either, applying a transformation to the error.

Example:

result := either.TryCatch(
    42, nil,
    func(err error) string { return err.Error() },
) // Right(42)

func TryCatchError

func TryCatchError[A any](val A, err error) Either[error, A]

TryCatchError is a specialized version of TryCatch for error types. Converts a (value, error) tuple into Either[error, A].

Example:

result := either.TryCatchError(42, nil) // Right(42)
result := either.TryCatchError(0, errors.New("fail")) // Left(error)

func (Either[E, A]) Format

func (s Either[E, A]) Format(f fmt.State, c rune)

Format implements fmt.Formatter for Either. Supports all standard format verbs:

  • %s, %v, %+v: uses String() representation
  • %#v: uses GoString() representation
  • %q: quoted String() representation
  • other verbs: uses String() representation

Example:

e := either.Right[error](42)
fmt.Printf("%s", e)   // "Right[int](42)"
fmt.Printf("%v", e)   // "Right[int](42)"
fmt.Printf("%#v", e)  // "either.Right[error](42)"
Example

ExampleEither_Format demonstrates the fmt.Formatter interface implementation.

package main

import (
	"fmt"

	E "github.com/IBM/fp-go/v2/either"
)

func main() {
	result := E.Right[error](42)

	// Different format verbs
	fmt.Printf("%%s: %s\n", result)
	fmt.Printf("%%v: %v\n", result)
	fmt.Printf("%%+v: %+v\n", result)
	fmt.Printf("%%#v: %#v\n", result)

}
Output:

%s: Right[int](42)
%v: Right[int](42)
%+v: Right[int](42)
%#v: either.Right[error](42)

func (Either[E, A]) GoString

func (s Either[E, A]) GoString() string

GoString implements fmt.GoStringer for Either. Returns a Go-syntax representation of the Either value.

Example:

either.Right[error](42).GoString() // "either.Right[error](42)"
either.Left[int](errors.New("fail")).GoString() // "either.Left[int](error)"
Example

ExampleEither_GoString demonstrates the fmt.GoStringer interface implementation.

package main

import (
	"errors"
	"fmt"

	E "github.com/IBM/fp-go/v2/either"
)

func main() {
	right := E.Right[error](42)
	left := E.Left[int](errors.New("error"))

	fmt.Printf("%#v\n", right)
	fmt.Printf("%#v\n", left)

}
Output:

either.Right[error](42)
either.Left[int](&errors.errorString{s:"error"})

func (Either[E, A]) LogValue

func (s Either[E, A]) LogValue() slog.Value

LogValue implements slog.LogValuer for Either. Returns a slog.Value that represents the Either for structured logging. Returns a group value with "right" key for Right values and "left" key for Left values.

Example:

logger := slog.Default()
result := either.Right[error](42)
logger.Info("result", "value", result)
// Logs: {"msg":"result","value":{"right":42}}

err := either.Left[int](errors.New("failed"))
logger.Error("error", "value", err)
// Logs: {"msg":"error","value":{"left":"failed"}}
Example

ExampleEither_LogValue demonstrates the slog.LogValuer interface implementation.

package main

import (
	"errors"
	"log/slog"
	"os"

	E "github.com/IBM/fp-go/v2/either"
)

func main() {
	logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
		Level: slog.LevelInfo,
		ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
			// Remove time for consistent output
			if a.Key == slog.TimeKey {
				return slog.Attr{}
			}
			return a
		},
	}))

	// Right value
	rightResult := E.Right[error](42)
	logger.Info("computation succeeded", "result", rightResult)

	// Left value
	leftResult := E.Left[int](errors.New("computation failed"))
	logger.Error("computation failed", "result", leftResult)

}
Output:

level=INFO msg="computation succeeded" result.right=42
level=ERROR msg="computation failed" result.left="computation failed"
Example (Structured)

ExampleEither_LogValue_structured demonstrates structured logging with Either.

package main

import (
	"errors"
	"log/slog"
	"os"

	E "github.com/IBM/fp-go/v2/either"
)

func main() {
	logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
		Level: slog.LevelInfo,
		ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
			if a.Key == slog.TimeKey {
				return slog.Attr{}
			}
			return a
		},
	}))

	// Simulate a computation pipeline
	compute := func(x int) E.Either[error, int] {
		if x < 0 {
			return E.Left[int](errors.New("negative input"))
		}
		return E.Right[error](x * 2)
	}

	// Log successful computation
	result1 := compute(21)
	logger.Info("computation", "input", 21, "output", result1)

	// Log failed computation
	result2 := compute(-5)
	logger.Error("computation", "input", -5, "output", result2)

}
Output:

level=INFO msg=computation input=21 output.right=42
level=ERROR msg=computation input=-5 output.left="negative input"

func (Either[E, A]) String

func (s Either[E, A]) String() string

String prints some debug info for the object

Example

ExampleEither_String demonstrates the fmt.Stringer interface implementation.

package main

import (
	"errors"
	"fmt"

	E "github.com/IBM/fp-go/v2/either"
)

func main() {
	right := E.Right[error](42)
	left := E.Left[int](errors.New("something went wrong"))

	fmt.Println(right.String())
	fmt.Println(left.String())

}
Output:

Right[int](42)
Left[*errors.errorString](something went wrong)

type Endomorphism

type Endomorphism[T any] = endomorphism.Endomorphism[T]

Option is a type alias for option.Option, provided for convenience when working with Either and Option together.

func ApSL

func ApSL[E, S, T any](
	lens Lens[S, T],
	fa Either[E, T],
) Endomorphism[Either[E, S]]

ApSL attaches a value to a context using a lens-based setter. This is a convenience function that combines ApS with a lens, allowing you to use optics to update nested structures in a more composable way.

The lens parameter provides both the getter and setter for a field within the structure S. This eliminates the need to manually write setter functions and enables working with nested fields in a type-safe manner.

Unlike BindL, ApSL uses applicative semantics, meaning the computation fa is independent of the current state and can be evaluated concurrently.

Type Parameters:

  • E: Error type for the Either
  • S: Structure type containing the field to update
  • T: Type of the field being updated

Parameters:

  • lens: A Lens[S, T] that focuses on a field of type T within structure S
  • fa: An Either[E, T] computation that produces the value to set

Returns:

  • An endomorphism that updates the focused field in the Either context

Example:

type Person struct {
    Name string
    Age  int
}

ageLens := lens.MakeLens(
    func(p Person) int { return p.Age },
    func(p Person, a int) Person { p.Age = a; return p },
)

result := F.Pipe2(
    either.Right[error](Person{Name: "Alice", Age: 25}),
    either.ApSL(ageLens, either.Right[error](30)),
) // Right(Person{Name: "Alice", Age: 30})

func BindL

func BindL[E, S, T any](
	lens Lens[S, T],
	f Kleisli[E, T, T],
) Endomorphism[Either[E, S]]

BindL attaches the result of a computation to a context using a lens-based setter. This is a convenience function that combines Bind with a lens, allowing you to use optics to update nested structures based on their current values.

The lens parameter provides both the getter and setter for a field within the structure S. The computation function f receives the current value of the focused field and returns an Either that produces the new value.

Unlike ApSL, BindL uses monadic sequencing, meaning the computation f can depend on the current value of the focused field.

Type Parameters:

  • E: Error type for the Either
  • S: Structure type containing the field to update
  • T: Type of the field being updated

Parameters:

  • lens: A Lens[S, T] that focuses on a field of type T within structure S
  • f: A function that takes the current field value and returns an Either[E, T]

Returns:

  • An endomorphism that updates the focused field based on its current value

Example:

type Counter struct {
    Value int
}

valueLens := lens.MakeLens(
    func(c Counter) int { return c.Value },
    func(c Counter, v int) Counter { c.Value = v; return c },
)

// Increment the counter, but fail if it would exceed 100
increment := func(v int) either.Either[error, int] {
    if v >= 100 {
        return either.Left[int](errors.New("counter overflow"))
    }
    return either.Right[error](v + 1)
}

result := F.Pipe1(
    either.Right[error](Counter{Value: 42}),
    either.BindL(valueLens, increment),
) // Right(Counter{Value: 43})

func LetL

func LetL[E, S, T any](
	lens Lens[S, T],
	f Endomorphism[T],
) Endomorphism[Either[E, S]]

LetL attaches the result of a pure computation to a context using a lens-based setter. This is a convenience function that combines Let with a lens, allowing you to use optics to update nested structures with pure transformations.

The lens parameter provides both the getter and setter for a field within the structure S. The transformation function f receives the current value of the focused field and returns the new value directly (not wrapped in Either).

This is useful for pure transformations that cannot fail, such as mathematical operations, string manipulations, or other deterministic updates.

Type Parameters:

  • E: Error type for the Either
  • S: Structure type containing the field to update
  • T: Type of the field being updated

Parameters:

  • lens: A Lens[S, T] that focuses on a field of type T within structure S
  • f: An endomorphism (T → T) that transforms the current field value

Returns:

  • An endomorphism that updates the focused field with the transformed value

Example:

type Counter struct {
    Value int
}

valueLens := lens.MakeLens(
    func(c Counter) int { return c.Value },
    func(c Counter, v int) Counter { c.Value = v; return c },
)

// Double the counter value
double := func(v int) int { return v * 2 }

result := F.Pipe1(
    either.Right[error](Counter{Value: 21}),
    either.LetL(valueLens, double),
) // Right(Counter{Value: 42})

func LetToL

func LetToL[E, S, T any](
	lens Lens[S, T],
	b T,
) Endomorphism[Either[E, S]]

LetToL attaches a constant value to a context using a lens-based setter. This is a convenience function that combines LetTo with a lens, allowing you to use optics to set nested fields to specific values.

The lens parameter provides the setter for a field within the structure S. Unlike LetL which transforms the current value, LetToL simply replaces it with the provided constant value b.

This is useful for resetting fields, initializing values, or setting fields to predetermined constants.

Type Parameters:

  • E: Error type for the Either
  • S: Structure type containing the field to update
  • T: Type of the field being updated

Parameters:

  • lens: A Lens[S, T] that focuses on a field of type T within structure S
  • b: The constant value to set the field to

Returns:

  • An endomorphism that sets the focused field to the constant value

Example:

type Config struct {
    Debug   bool
    Timeout int
}

debugLens := lens.MakeLens(
    func(c Config) bool { return c.Debug },
    func(c Config, d bool) Config { c.Debug = d; return c },
)

result := F.Pipe1(
    either.Right[error](Config{Debug: true, Timeout: 30}),
    either.LetToL(debugLens, false),
) // Right(Config{Debug: false, Timeout: 30})

type Kleisli

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

Option is a type alias for option.Option, provided for convenience when working with Either and Option together.

func TailRec

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

func TraverseArray

func TraverseArray[E, A, B any](f Kleisli[E, A, B]) Kleisli[E, []A, []B]

TraverseArray transforms an array by applying a function that returns an Either to each element. If any element produces a Left, the entire result is that Left (short-circuits). Otherwise, returns Right containing the array of all Right values.

Example:

parse := func(s string) either.Either[error, int] {
    v, err := strconv.Atoi(s)
    return either.FromError(v, err)
}
result := either.TraverseArray(parse)([]string{"1", "2", "3"})
// result is Right([]int{1, 2, 3})

func TraverseArrayG

func TraverseArrayG[GA ~[]A, GB ~[]B, E, A, B any](f Kleisli[E, A, B]) Kleisli[E, GA, GB]

TraverseArrayG transforms an array by applying a function that returns an Either to each element. If any element produces a Left, the entire result is that Left (short-circuits). Otherwise, returns Right containing the array of all Right values. The G suffix indicates support for generic slice types.

Example:

parse := func(s string) either.Either[error, int] {
    v, err := strconv.Atoi(s)
    return either.FromError(v, err)
}
result := either.TraverseArrayG[[]string, []int](parse)([]string{"1", "2", "3"})
// result is Right([]int{1, 2, 3})

func TraverseArrayWithIndex

func TraverseArrayWithIndex[E, A, B any](f func(int, A) Either[E, B]) Kleisli[E, []A, []B]

TraverseArrayWithIndex transforms an array by applying an indexed function that returns an Either. The function receives both the index and the element. If any element produces a Left, the entire result is that Left (short-circuits).

Example:

validate := func(i int, s string) either.Either[error, string] {
    if S.IsNonEmpty(s) {
        return either.Right[error](fmt.Sprintf("%d:%s", i, s))
    }
    return either.Left[string](fmt.Errorf("empty at index %d", i))
}
result := either.TraverseArrayWithIndex(validate)([]string{"a", "b"})
// result is Right([]string{"0:a", "1:b"})

func TraverseArrayWithIndexG

func TraverseArrayWithIndexG[GA ~[]A, GB ~[]B, E, A, B any](f func(int, A) Either[E, B]) Kleisli[E, GA, GB]

TraverseArrayWithIndexG transforms an array by applying an indexed function that returns an Either. The function receives both the index and the element. If any element produces a Left, the entire result is that Left (short-circuits). The G suffix indicates support for generic slice types.

Example:

validate := func(i int, s string) either.Either[error, string] {
    if S.IsNonEmpty(s) {
        return either.Right[error](fmt.Sprintf("%d:%s", i, s))
    }
    return either.Left[string](fmt.Errorf("empty at index %d", i))
}
result := either.TraverseArrayWithIndexG[[]string, []string](validate)([]string{"a", "b"})
// result is Right([]string{"0:a", "1:b"})

func TraverseRecord

func TraverseRecord[K comparable, E, A, B any](f Kleisli[E, A, B]) Kleisli[E, map[K]A, map[K]B]

TraverseRecord transforms a map by applying a function that returns an Either to each value. If any value produces a Left, the entire result is that Left (short-circuits). Otherwise, returns Right containing the map of all Right values.

Example:

parse := func(s string) either.Either[error, int] {
    v, err := strconv.Atoi(s)
    return either.FromError(v, err)
}
result := either.TraverseRecord[string](parse)(map[string]string{"a": "1", "b": "2"})
// result is Right(map[string]int{"a": 1, "b": 2})

func TraverseRecordG

func TraverseRecordG[GA ~map[K]A, GB ~map[K]B, K comparable, E, A, B any](f Kleisli[E, A, B]) Kleisli[E, GA, GB]

TraverseRecordG transforms a map by applying a function that returns an Either to each value. If any value produces a Left, the entire result is that Left (short-circuits). Otherwise, returns Right containing the map of all Right values. The G suffix indicates support for generic map types.

Example:

parse := func(s string) either.Either[error, int] {
    v, err := strconv.Atoi(s)
    return either.FromError(v, err)
}
result := either.TraverseRecordG[map[string]string, map[string]int](parse)(map[string]string{"a": "1", "b": "2"})
// result is Right(map[string]int{"a": 1, "b": 2})

func TraverseRecordWithIndex

func TraverseRecordWithIndex[K comparable, E, A, B any](f func(K, A) Either[E, B]) Kleisli[E, map[K]A, map[K]B]

TraverseRecordWithIndex transforms a map by applying an indexed function that returns an Either. The function receives both the key and the value. If any value produces a Left, the entire result is that Left (short-circuits).

Example:

validate := func(k string, v string) either.Either[error, string] {
    if len(v) > 0 {
        return either.Right[error](k + ":" + v)
    }
    return either.Left[string](fmt.Errorf("empty value for key %s", k))
}
result := either.TraverseRecordWithIndex[string](validate)(map[string]string{"a": "1"})
// result is Right(map[string]string{"a": "a:1"})

func TraverseRecordWithIndexG

func TraverseRecordWithIndexG[GA ~map[K]A, GB ~map[K]B, K comparable, E, A, B any](f func(K, A) Either[E, B]) Kleisli[E, GA, GB]

TraverseRecordWithIndexG transforms a map by applying an indexed function that returns an Either. The function receives both the key and the value. If any value produces a Left, the entire result is that Left (short-circuits). The G suffix indicates support for generic map types.

Example:

validate := func(k string, v string) either.Either[error, string] {
    if len(v) > 0 {
        return either.Right[error](k + ":" + v)
    }
    return either.Left[string](fmt.Errorf("empty value for key %s", k))
}
result := either.TraverseRecordWithIndexG[map[string]string, map[string]string](validate)(map[string]string{"a": "1"})
// result is Right(map[string]string{"a": "a:1"})

func WithResource

func WithResource[A, E, R, ANY any](
	onCreate func() Either[E, R],
	onRelease Kleisli[E, R, ANY],
) Kleisli[E, Kleisli[E, R, A], A]

WithResource constructs a function that creates a resource, operates on it, and then releases it. This ensures proper resource cleanup even if operations fail. The resource is released immediately after the operation completes.

Parameters:

  • onCreate: Function to create/acquire the resource
  • onRelease: Function to release/cleanup the resource

Returns a function that takes an operation to perform on the resource.

Example:

withFile := either.WithResource(
    func() either.Either[error, *os.File] {
        return either.TryCatchError(os.Open("file.txt"))
    },
    func(f *os.File) either.Either[error, any] {
        return either.TryCatchError(f.Close())
    },
)
result := withFile(func(f *os.File) either.Either[error, string] {
    // Use file here
    return either.Right[error]("data")
})

type Lazy

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

Option is a type alias for option.Option, provided for convenience when working with Either and Option together.

type Lens

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

Option is a type alias for option.Option, provided for convenience when working with Either and Option together.

type Monoid

type Monoid[E, A any] = monoid.Monoid[Either[E, A]]

Option is a type alias for option.Option, provided for convenience when working with Either and Option together.

func AltMonoid

func AltMonoid[E, A any](zero Lazy[Either[E, A]]) Monoid[E, A]

AltMonoid creates a monoid for Either using the Alt operation. The empty value is provided as a lazy computation. When combining, returns the first Right value, or the second if the first is Left.

Example:

zero := func() either.Either[error, int] { return either.Left[int](errors.New("empty")) }
m := either.AltMonoid[error, int](zero)
result := m.Concat(either.Left[int](errors.New("err1")), either.Right[error](42))
// result is Right(42)

func AlternativeMonoid

func AlternativeMonoid[E, A any](m M.Monoid[A]) Monoid[E, A]

AlternativeMonoid creates a monoid for Either using applicative semantics. The empty value is Right with the monoid's empty value. Combines values using applicative operations.

Example:

import "github.com/IBM/fp-go/v2/monoid"
intAdd := monoid.MakeMonoid(0, func(a, b int) int { return a + b })
m := either.AlternativeMonoid[error](intAdd)
result := m.Concat(either.Right[error](1), either.Right[error](2))
// result is Right(3)

type Operator

type Operator[E, A, B any] = Kleisli[E, Either[E, A], B]

Option is a type alias for option.Option, provided for convenience when working with Either and Option together.

func Alt

func Alt[E, A any](that Lazy[Either[E, A]]) Operator[E, A, A]

Alt provides an alternative Either if the first is Left.

Example:

alternative := either.Alt[error](func() either.Either[error, int] {
    return either.Right[error](99)
})
result := alternative(either.Left[int](errors.New("fail"))) // Right(99)

func Ap

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

Ap is the curried version of MonadAp. Returns a function that applies a wrapped function to the given wrapped value.

func ApS

func ApS[E, S1, S2, T any](
	setter func(T) func(S1) S2,
	fa Either[E, T],
) Operator[E, S1, S2]

ApS attaches a value to a context S1 to produce a context S2 by considering the context and the value concurrently. Uses applicative semantics rather than monadic sequencing.

Example:

type State struct { x, y int }
result := F.Pipe2(
    either.Right[error](State{x: 10}),
    either.ApS(
        func(y int) func(State) State {
            return func(s State) State { return State{x: s.x, y: y} }
        },
        either.Right[error](32),
    ),
) // Right(State{x: 10, y: 32})

func Bind

func Bind[E, S1, S2, T any](
	setter func(T) func(S1) S2,
	f Kleisli[E, S1, T],
) Operator[E, S1, S2]

Bind attaches the result of a computation to a context S1 to produce a context S2. This enables building up complex computations in a pipeline.

Example:

type State struct { value int }
result := F.Pipe2(
    either.Do[error](State{}),
    either.Bind(
        func(v int) func(State) State {
            return func(s State) State { return State{value: v} }
        },
        func(s State) either.Either[error, int] {
            return either.Right[error](42)
        },
    ),
)

func BindTo

func BindTo[E, S1, T any](
	setter func(T) S1,
) Operator[E, T, S1]

BindTo initializes a new state S1 from a value T. This is typically used to start a bind chain.

Example:

type State struct { value int }
result := F.Pipe2(
    either.Right[error](42),
    either.BindTo(func(v int) State { return State{value: v} }),
) // Right(State{value: 42})

func Chain

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

Chain is the curried version of MonadChain. Sequences two computations where the second depends on the first.

func ChainFirst

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

ChainFirst is the curried version of MonadChainFirst.

func ChainTo

func ChainTo[A, E, B any](mb Either[E, B]) Operator[E, A, B]

ChainTo is the curried version of MonadChainTo.

func Flap

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

Flap is the curried version of MonadFlap.

func Let

func Let[E, S1, S2, T any](
	key func(T) func(S1) S2,
	f func(S1) T,
) Operator[E, S1, S2]

Let attaches the result of a pure computation to a context S1 to produce a context S2. Similar to Bind but for pure (non-Either) computations.

Example:

type State struct { value int }
result := F.Pipe2(
    either.Right[error](State{value: 10}),
    either.Let(
        func(v int) func(State) State {
            return func(s State) State { return State{value: s.value + v} }
        },
        func(s State) int { return 32 },
    ),
) // Right(State{value: 42})

func LetTo

func LetTo[E, S1, S2, T any](
	key func(T) func(S1) S2,
	b T,
) Operator[E, S1, S2]

LetTo attaches a constant value to a context S1 to produce a context S2.

Example:

type State struct { name string }
result := F.Pipe2(
    either.Right[error](State{}),
    either.LetTo(
        func(n string) func(State) State {
            return func(s State) State { return State{name: n} }
        },
        "Alice",
    ),
) // Right(State{name: "Alice"})

func Map

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

Map is the curried version of MonadMap. Transforms the Right value using the provided function.

func MapTo

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

MapTo is the curried version of MonadMapTo.

func OrElse

func OrElse[E, A any](onLeft Kleisli[E, E, A]) Operator[E, A, A]

OrElse recovers from a Left by providing an alternative computation.

Example:

recover := either.OrElse(func(err error) either.Either[error, int] {
    return either.Right[error](0) // default value
})
result := recover(either.Left[int](errors.New("fail"))) // Right(0)

type Option

type Option[A any] = option.Option[A]

Option is a type alias for option.Option, provided for convenience when working with Either and Option together.

func ToOption

func ToOption[E, A any](ma Either[E, A]) Option[A]

ToOption converts an Either to an Option, discarding the Left value.

Example:

result := either.ToOption(either.Right[error](42)) // Some(42)
result := either.ToOption(either.Left[int](errors.New("err"))) // None

Directories

Path Synopsis
Package exec provides utilities for executing system commands with Either-based error handling.
Package exec provides utilities for executing system commands with Either-based error handling.
Package http provides utilities for creating HTTP requests with Either-based error handling.
Package http provides utilities for creating HTTP requests with Either-based error handling.
Package testing provides utilities for testing Either monad laws.
Package testing provides utilities for testing Either monad laws.

Jump to

Keyboard shortcuts

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