common

package
v2.3.122 Latest Latest
Warning

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

Go to latest
Published: Sep 2, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

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

Package either provides implementations of the Either type and related operations.

This package implements several Fantasy Land algebraic structures:

The Filterable specification defines operations for filtering and partitioning data structures based on predicates and mapping functions.

package option implements the Option monad, a data type that can have a defined value or none

Package optional provides an optic for focusing on values that may not exist.

Overview

Optional is an optic used to zoom inside a product. Unlike the Lens, the element that the Optional focuses on may not exist. An Optional[S, A] represents a relationship between a source type S and a focus type A, where the focus may or may not be present.

Optional Laws

An Optional must satisfy the following laws, which are consistent with other functional programming libraries such as monocle-ts (https://gcanti.github.io/monocle-ts/modules/Optional.ts.html) and the Haskell lens library (https://hackage.haskell.org/package/lens):

  1. GetSet Law (No-op on None): If GetOption(s) returns None, then Set(a)(s) must return s unchanged (no-op). This ensures that attempting to update a value that doesn't exist has no effect.

    Formally: GetOption(s) = None => Set(a)(s) = s

  2. SetGet Law (Get what you Set): If GetOption(s) returns Some(_), then GetOption(Set(a)(s)) must return Some(a). This ensures that after setting a value, you can retrieve it.

    Formally: GetOption(s) = Some(_) => GetOption(Set(a)(s)) = Some(a)

  3. SetSet Law (Last Set Wins): Setting twice is the same as setting once with the final value.

    Formally: Set(b)(Set(a)(s)) = Set(b)(s)

No-op Behavior

A key property of Optional is that updating a value for which GetOption returns None is a no-op. This behavior is implemented through the optionalModify function, which only applies the modification if the optional value exists. When GetOption returns None, the original structure is returned unchanged.

This is consistent with the behavior in:

  • monocle-ts: Optional.modify returns the original value when the optional doesn't match
  • Haskell lens: over and set operations are no-ops when the traversal finds no targets

Example

type Person struct {
    Name string
    Age  int
}

// Create an optional that focuses on non-empty names
nameOptional := MakeOptional(
    func(p Person) option.Option[string] {
        if p.Name != "" {
            return option.Some(p.Name)
        }
        return option.None[string]()
    },
    func(p Person, name string) Person {
        p.Name = name
        return p
    },
)

// When the optional matches, Set updates the value
person1 := Person{Name: "Alice", Age: 30}
updated1 := nameOptional.Set("Bob")(person1)
// updated1.Name == "Bob"

// When the optional doesn't match (Name is empty), Set is a no-op
person2 := Person{Name: "", Age: 30}
updated2 := nameOptional.Set("Bob")(person2)
// updated2 == person2 (unchanged)

Package prism provides utilities for converting prisms to optionals and working with Option types.

This package bridges the gap between prisms (which focus on sum types) and optionals (which focus on values that may not exist). The key functions allow you to:

  • Convert any prism into an optional using AsOptional
  • Focus on the Some variant of Option types using Some

These conversions maintain the optional laws, ensuring that the resulting optionals behave correctly with respect to GetOption and Set operations.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func EitherApV added in v2.3.122

func EitherApV[B, A, E any](sg S.Semigroup[E]) func(Either[E, A]) EitherOperator[E, func(A) B, B]

EitherApV is the curried version of EitherMonadApV 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 EitherMonadApV, 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.EitherLeft[int](ValidationError{Errors: []string{"must be positive"}})
}

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

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

func EitherBiMap added in v2.3.122

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

EitherBiMap is the curried version of EitherMonadBiMap. Maps a pair of functions over the two type arguments of the bifunctor.

func EitherChainOptionK added in v2.3.122

func EitherChainOptionK[A, B, E any](onNone func() E) func(func(A) Option[B]) EitherOperator[E, A, B]

EitherChainOptionK is the curried version of EitherMonadChainOptionK.

func EitherCompactArray added in v2.3.122

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

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

Example:

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

func EitherCompactArrayG added in v2.3.122

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

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

Example:

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

func EitherCompactRecord added in v2.3.122

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

EitherCompactRecord 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.EitherCompactRecord(eithers)
// result is map[string]int{"a": 1, "c": 3}

func EitherCompactRecordG added in v2.3.122

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

EitherCompactRecordG 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.EitherCompactRecordG[map[string]either.Either[error, int], map[string]int](eithers)
// result is map[string]int{"a": 1, "c": 3}

func EitherFold added in v2.3.122

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

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

Example:

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

func EitherFromError added in v2.3.122

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

EitherFromError 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.EitherFromError(validate)
result := toEither(42) // Right(42)

func EitherFromOption added in v2.3.122

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

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

Example:

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

func EitherGetOrElse added in v2.3.122

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

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

Example:

result := either.EitherGetOrElse(func(err error) int { return 0 })(either.EitherRight[error](42)) // 42
result := either.EitherGetOrElse(func(err error) int { return 0 })(either.EitherLeft[int](err)) // 0

func EitherIsLeft added in v2.3.122

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

EitherIsLeft tests if the Either is a Left value. Rather use EitherFold or EitherMonadFold if you need to access the values. Inverse is EitherIsRight.

Example:

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

func EitherIsRight added in v2.3.122

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

EitherIsRight tests if the Either is a Right value. Rather use EitherFold or EitherMonadFold if you need to access the values. Inverse is EitherIsLeft.

Example:

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

func EitherMapLeft added in v2.3.122

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

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

func EitherMonadApV added in v2.3.122

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

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

Unlike the standard [MonadAp] which short-circuits on the first Left (error), EitherMonadApV 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.EitherMonadApV[int](errorSemigroup)

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

// One error - returns that error
fab2 := either.Right[string](N.Mul(2))
fa2 := either.EitherLeft[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 EitherMonadFold added in v2.3.122

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

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

Example:

result := either.EitherMonadFold(
    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 EitherPartition added in v2.3.122

func EitherPartition[E, A any](p Predicate[A], empty E) func(Either[E, A]) Pair[Either[E, A], Either[E, A]]

EitherPartition separates an Either value into a Pair based on a predicate function. It returns a function that takes an Either and produces a Pair of Either values, where the first element contains values that fail the predicate and the second contains values that pass the predicate.

This function implements the Filterable specification's partition operation: https://github.com/fantasyland/fantasy-land#filterable

The behavior is as follows:

  • If the input is Left, both elements of the resulting Pair will be the same Left value
  • If the input is Right and the predicate returns true, the result is (Left(empty), Right(value))
  • If the input is Right and the predicate returns false, the result is (Right(value), Left(empty))

This function is useful for separating Either values into two categories based on a condition, commonly used in filtering operations where you want to keep track of both the values that pass and fail a test.

Parameters:

  • p: A predicate function that tests values of type A
  • empty: The default Left value to use when creating Left instances for partitioning

Returns:

A function that takes an Either[E, A] and returns a Pair where:
  - First element: Either values that fail the predicate (or original Left)
  - Second element: Either values that pass the predicate (or original Left)

Example:

import (
    E "github.com/IBM/fp-go/v2/either"
    N "github.com/IBM/fp-go/v2/number"
    P "github.com/IBM/fp-go/v2/pair"
)

// EitherPartition positive and non-positive numbers
isPositive := N.MoreThan(0)
partition := E.EitherPartition(isPositive, "not positive")

// Right value that passes predicate
result1 := partition(E.Right[string](5))
// result1 = Pair(Left("not positive"), Right(5))
left1, right1 := P.Unpack(result1)
// left1 = Left("not positive"), right1 = Right(5)

// Right value that fails predicate
result2 := partition(E.Right[string](-3))
// result2 = Pair(Right(-3), Left("not positive"))
left2, right2 := P.Unpack(result2)
// left2 = Right(-3), right2 = Left("not positive")

// Left value passes through unchanged in both positions
result3 := partition(E.EitherLeft[int]("error"))
// result3 = Pair(Left("error"), Left("error"))
left3, right3 := P.Unpack(result3)
// left3 = Left("error"), right3 = Left("error")

func EitherPartitionMap added in v2.3.122

func EitherPartitionMap[E, A, B, C any](f EitherKleisli[B, A, C], empty E) func(Either[E, A]) Pair[Either[E, B], Either[E, C]]

EitherPartitionMap separates and transforms an Either value into a Pair of Either values using a mapping function. It returns a function that takes an Either[E, A] and produces a Pair of Either values, where the mapping function f transforms the Right value into Either[B, C]. The result is partitioned based on whether f produces a Left or Right value.

This function implements the Filterable specification's partitionMap operation: https://github.com/fantasyland/fantasy-land#filterable

The behavior is as follows:

  • If the input is Left, both elements of the resulting Pair will be Left with the original error
  • If the input is Right and f returns Left(B), the result is (Right(B), Left(empty))
  • If the input is Right and f returns Right(C), the result is (Left(empty), Right(C))

This function is useful for operations that need to categorize and transform values simultaneously, such as separating valid and invalid data while applying different transformations to each category.

Parameters:

  • f: A Kleisli function that transforms values of type A to Either[B, C]
  • empty: The default error value to use when creating Left instances for partitioning

Returns:

A function that takes an Either[E, A] and returns a Pair[Either[E, B], Either[E, C]] where:
  - If input is Left: (Left(original_error), Left(original_error))
  - If f returns Left(B): (Right(B), Left(empty))
  - If f returns Right(C): (Left(empty), Right(C))

Example:

import (
    E "github.com/IBM/fp-go/v2/either"
    P "github.com/IBM/fp-go/v2/pair"
)

// Classify and transform numbers: negative -> error message, positive -> squared value
classifyNumber := func(n int) Either[string, int] {
    if n < 0 {
        return E.EitherLeft[int]("negative: " + strconv.Itoa(n))
    }
    return E.Right[string](n * n)
}
partitionMap := E.EitherPartitionMap(classifyNumber, "not classified")

// Positive number - goes to right side as squared value
result1 := partitionMap(E.Right[string](5))
// result1 = Pair(Left("not classified"), Right(25))
left1, right1 := P.Unpack(result1)
// left1 = Left("not classified"), right1 = Right(25)

// Negative number - goes to left side with error message
result2 := partitionMap(E.Right[string](-3))
// result2 = Pair(Right("negative: -3"), Left("not classified"))
left2, right2 := P.Unpack(result2)
// left2 = Right("negative: -3"), right2 = Left("not classified")

// Original Left value - appears in both positions
result3 := partitionMap(E.EitherLeft[int]("original error"))
// result3 = Pair(Left("original error"), Left("original error"))
left3, right3 := P.Unpack(result3)
// left3 = Left("original error"), right3 = Left("original error")

// Validate and transform user input
type ValidationError struct{ Field, Message string }
type User struct{ Name string; Age int }

validateUser := func(input map[string]string) Either[ValidationError, User] {
    name, hasName := input["name"]
    ageStr, hasAge := input["age"]
    if !hasName {
        return E.EitherLeft[User](ValidationError{"name", "missing"})
    }
    if !hasAge {
        return E.EitherLeft[User](ValidationError{"age", "missing"})
    }
    age, err := strconv.Atoi(ageStr)
    if err != nil {
        return E.EitherLeft[User](ValidationError{"age", "invalid"})
    }
    return E.Right[ValidationError](User{name, age})
}
partitionUsers := E.EitherPartitionMap(validateUser, ValidationError{"", "not processed"})

validInput := map[string]string{"name": "Alice", "age": "30"}
result4 := partitionUsers(E.Right[string](validInput))
// result4 = Pair(Left(ValidationError{"", "not processed"}), Right(User{"Alice", 30}))

invalidInput := map[string]string{"name": "Bob"}
result5 := partitionUsers(E.Right[string](invalidInput))
// result5 = Pair(Right(ValidationError{"age", "missing"}), Left(ValidationError{"", "not processed"}))

func EitherReduce added in v2.3.122

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

EitherReduce 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 EitherSequence2 added in v2.3.122

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

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

func EitherSequence3 added in v2.3.122

func EitherSequence3[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]

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

func EitherToError added in v2.3.122

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

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

Example:

err := either.EitherToError(either.EitherLeft[int](errors.New("fail"))) // error
err := either.EitherToError(either.EitherRight[error](42)) // nil

func EitherToType added in v2.3.122

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

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

Example:

convert := either.EitherToType[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 EitherUnwrap added in v2.3.122

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

EitherUnwrap 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.EitherUnwrap(either.Right[error](42)) // 42, nil
val, err := either.EitherUnwrap(either.Left[int](errors.New("fail"))) // 0, error

func EitherUnwrapError added in v2.3.122

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

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

Example:

val, err := either.EitherUnwrapError(either.EitherRight[error](42)) // 42, nil
val, err := either.EitherUnwrapError(either.EitherLeft[int](errors.New("fail"))) // zero, error

func IsoComposeIso

func IsoComposeIso[S, A, B any](ab Iso[A, B]) func(Iso[S, A]) Iso[S, B]

IsoComposeIso combines two isomorphisms to create a new isomorphism. Given Iso[S, A] and Iso[A, B], creates Iso[S, B]. The resulting isomorphism first applies the outer iso (S → A), then the inner iso (A → B).

Type Parameters:

  • S: The outermost source type
  • A: The intermediate type
  • B: The innermost target type

Parameters:

  • ab: The inner isomorphism (A → B)

Returns:

  • A function that takes the outer isomorphism (S → A) and returns the composed isomorphism (S → B)

Example:

metersToKm := MakeIso(
    func(m float64) float64 { return m / 1000 },
    func(km float64) float64 { return km * 1000 },
)

kmToMiles := MakeIso(
    func(km float64) float64 { return km * 0.621371 },
    func(mi float64) float64 { return mi / 0.621371 },
)

// IsoComposeIso: meters → kilometers → miles
metersToMiles := F.Pipe1(metersToKm, IsoComposeIso[float64](kmToMiles))

miles := metersToMiles.Get(5000)        // ~3.11 miles
meters := metersToMiles.ReverseGet(3.11) // ~5000 meters

func IsoComposeLens

func IsoComposeLens[S, A, B any](ab Lens[A, B]) func(Iso[S, A]) Lens[S, B]

IsoComposeLens combines an isomorphism with a lens to produce a new lens.

Given an isomorphism Iso[S, A] and a lens Lens[A, B], IsoComposeLens creates a Lens[S, B]. Internally the isomorphism is first converted to a Lens[S, A] via IsoAsLens, then composed with the provided lens using LensComposeLens.

This is useful when the outer view of a structure is captured by a total, invertible transformation (an iso) and you want to drill further into the result with a lens — for example, when S is a newtype wrapper around A and you need to focus on a field of A.

The resulting lens satisfies all three lens laws whenever both the isomorphism and the inner lens individually satisfy them.

The composition follows: (sa ∘ ab).Get(s) = ab.Get(sa.Get(s))

Type Parameters:

  • S: Outermost source type — the input to the resulting lens
  • A: Intermediate type — the target of the iso and the source of the inner lens
  • B: Inner focus type — the focus of the resulting lens

Parameters:

  • ab: Lens from A to B (inner lens)

Returns:

  • A function that takes an Iso[S, A] and returns a Lens[S, B]

Example:

type Celsius float64
type Thermometer struct{ Reading Celsius }

// Isomorphism: float64 ↔ Celsius
floatToCelsius := MakeIso(
    func(f float64) Celsius { return Celsius(f) },
    func(c Celsius) float64 { return float64(c) },
)

// Lens: Thermometer → Celsius (focuses on the Reading field)
readingLens := MakeLens(
    func(t Thermometer) Celsius { return t.Reading },
    func(t Thermometer, c Celsius) Thermometer { t.Reading = c; return t },
)

// Compose: float64 → Celsius → Thermometer.Reading (Celsius)
// Result type: Lens[float64, Celsius]
tempLens := F.Pipe1(floatToCelsius, IsoComposeLens[float64](readingLens))

t := Thermometer{Reading: 100}
reading := tempLens.Get(100.0)          // Celsius(100)
updated := tempLens.Set(Celsius(0))(0.0) // Thermometer{Reading: 0}

See Also:

  • IsoComposeIso: the variant that composes with an Iso[A, B] instead of a Lens[A, B]
  • LensComposeLens: the pure-lens equivalent
  • IsoAsLens: converts an Iso to a Lens directly

func IsoFrom

func IsoFrom[S, A any](a A) func(Iso[S, A]) S

IsoFrom wraps a target value into a source value using an isomorphism. This is an alias for Wrap, provided for semantic clarity when the direction of conversion is important.

Type Parameters:

  • S: The source type to convert from
  • A: The target type

Parameters:

  • a: The target value to convert

Returns:

  • A function that takes an Iso[S, A] and returns the converted value of type S

Example:

type Email string
type ValidatedEmail struct{ value Email }

emailIso := MakeIso(
    func(ve ValidatedEmail) Email { return ve.value },
    func(e Email) ValidatedEmail { return ValidatedEmail{value: e} },
)

// Convert from Email
validated := IsoFrom[ValidatedEmail](Email("admin@example.com"))(emailIso)
// ValidatedEmail{value: "admin@example.com"}

func IsoIMap

func IsoIMap[S, A, B any](ab func(A) B, ba func(B) A) func(Iso[S, A]) Iso[S, B]

IsoIMap bidirectionally maps the target type of an isomorphism. Given Iso[S, A] and functions A → B and B → A, creates Iso[S, B]. This allows you to transform both directions of an isomorphism.

Type Parameters:

  • S: The source type (unchanged)
  • A: The original target type
  • B: The new target type

Parameters:

  • ab: Function to map from A to B
  • ba: Function to map from B to A (inverse of ab)

Returns:

  • A function that transforms Iso[S, A] to Iso[S, B]

Example:

type Celsius float64
type Kelvin float64

celsiusIso := Id[Celsius]()

// Create isomorphism to Kelvin
celsiusToKelvin := F.Pipe1(
    celsiusIso,
    IsoIMap(
        func(c Celsius) Kelvin { return Kelvin(c + 273.15) },
        func(k Kelvin) Celsius { return Celsius(k - 273.15) },
    ),
)

kelvin := celsiusToKelvin.Get(Celsius(20))      // 293.15 K
celsius := celsiusToKelvin.ReverseGet(Kelvin(293.15)) // 20°C

Note: The functions ab and ba must be inverses of each other to maintain the isomorphism laws.

func IsoModify

func IsoModify[S any, FCT ~func(A) A, A any](f FCT) func(Iso[S, A]) Endomorphism[S]

IsoModify creates a function that applies a transformation in the target space. It converts the source value to the target type, applies the transformation, then converts back to the source type.

Type Parameters:

  • S: The source type
  • FCT: The transformation function type (A → A)
  • A: The target type

Parameters:

  • f: The transformation function to apply in the target space

Returns:

  • A function that takes an Iso[S, A] and returns an endomorphism (S → S)

Example:

type Meters float64
type Kilometers float64

mToKm := MakeIso(
    func(m Meters) Kilometers { return Kilometers(m / 1000) },
    func(km Kilometers) Meters { return Meters(km * 1000) },
)

// Double the distance in kilometers, result in meters
doubled := IsoModify[Meters](func(km Kilometers) Kilometers {
    return km * 2
})(mToKm)(Meters(5000))
// Result: Meters(10000)

func IsoTo

func IsoTo[A, S any](s S) func(Iso[S, A]) A

IsoTo extracts the target value from a source value using an isomorphism. This is an alias for Unwrap, provided for semantic clarity when the direction of conversion is important.

Type Parameters:

  • A: The target type to convert to
  • S: The source type

Parameters:

  • s: The source value to convert

Returns:

  • A function that takes an Iso[S, A] and returns the converted value of type A

Example:

type Email string
type ValidatedEmail struct{ value Email }

emailIso := MakeIso(
    func(ve ValidatedEmail) Email { return ve.value },
    func(e Email) ValidatedEmail { return ValidatedEmail{value: e} },
)

// Convert to Email
email := IsoTo[Email](ValidatedEmail{value: "user@example.com"})(emailIso)
// "user@example.com"

func IsoUnwrap

func IsoUnwrap[A, S any](s S) func(Iso[S, A]) A

IsoUnwrap extracts the target value from a source value using an isomorphism. This is a convenience function that applies the Get function of the isomorphism.

Type Parameters:

  • A: The target type to extract
  • S: The source type

Parameters:

  • s: The source value to unwrap

Returns:

  • A function that takes an Iso[S, A] and returns the unwrapped value of type A

Example:

type UserId int

userIdIso := MakeIso(
    func(id UserId) int { return int(id) },
    func(i int) UserId { return UserId(i) },
)

rawId := IsoUnwrap[int](UserId(42))(userIdIso) // 42

Note: This function is also available as To for semantic clarity.

func IsoWrap

func IsoWrap[S, A any](a A) func(Iso[S, A]) S

IsoWrap wraps a target value into a source value using an isomorphism. This is a convenience function that applies the ReverseGet function of the isomorphism.

Type Parameters:

  • S: The source type to wrap into
  • A: The target type

Parameters:

  • a: The target value to wrap

Returns:

  • A function that takes an Iso[S, A] and returns the wrapped value of type S

Example:

type UserId int

userIdIso := MakeIso(
    func(id UserId) int { return int(id) },
    func(i int) UserId { return UserId(i) },
)

userId := IsoWrap[UserId](42)(userIdIso) // UserId(42)

Note: This function is also available as From for semantic clarity.

func LensComposePrism added in v2.3.122

func LensComposePrism[S, A, B any](p Prism[A, B]) func(Lens[S, A]) Optional[S, B]

LensComposePrism composes a Lens with a Prism to create an Optional.

This composition allows you to focus on a part of a structure (using a Lens) and then optionally extract a variant from that part (using a Prism). The result is an Optional because the Prism may not match the focused value.

The composition follows the Optional laws (a relaxed form of lens laws):

SetGet Law (GetSet for Optional):

  • If optional.GetOption(s) = Some(b), then optional.GetOption(optional.Set(b)(s)) = Some(b)
  • This ensures that setting a value and then getting it returns the same value

GetSet Law (for Optional):

  • If optional.GetOption(s) = None, then optional.Set(b)(s) = s (no-op)
  • This ensures that setting a value when the optional doesn't match leaves the structure unchanged

These laws are documented in the official fp-ts documentation: https://gcanti.github.io/monocle-ts/modules/Optional.ts.html

Type Parameters:

  • S: The source/outer structure type
  • A: The intermediate type (focused by the Lens)
  • B: The target type (focused by the Prism within A)

Parameters:

  • p: A Prism[A, B] that optionally extracts B from A

Returns:

  • A function that takes a Lens[S, A] and returns an Optional[S, B]

Behavior:

  • GetOption: First uses the Lens to get A from S, then uses the Prism to try to extract B from A. Returns Some(b) if both operations succeed, None otherwise.
  • Set: When setting a value b:
  • If GetOption(s) returns Some(_), it means the Prism matches, so we: 1. Use Prism.ReverseGet to construct an A from b 2. Use Lens.Set to update S with the new A
  • If GetOption(s) returns None, the Prism doesn't match, so we return s unchanged (no-op)

Example:

type Config struct {
    Database DatabaseConfig
}

type DatabaseConfig struct {
    Connection ConnectionType
}

type ConnectionType interface{ isConnection() }
type PostgreSQL struct{ Host string }
type MySQL struct{ Host string }

// Lens to focus on Database field
dbLens := lens.MakeLens(
    func(c Config) DatabaseConfig { return c.Database },
    func(c Config, db DatabaseConfig) Config { c.Database = db; return c },
)

// Prism to extract PostgreSQL from ConnectionType
pgPrism := prism.MakePrism(
    func(ct ConnectionType) OptionOption[PostgreSQL] {
        if pg, ok := ct.(PostgreSQL); ok {
            return OptionSome(pg)
        }
        return OptionNone[PostgreSQL]()
    },
    func(pg PostgreSQL) ConnectionType { return pg },
)

// LensComposePrism to create Optional[Config, PostgreSQL]
configPgOptional := LensComposePrism[Config, DatabaseConfig, PostgreSQL](pgPrism)(dbLens)

config := Config{Database: DatabaseConfig{Connection: PostgreSQL{Host: "localhost"}}}
host := configPgOptional.GetOption(config)  // Some(PostgreSQL{Host: "localhost"})

updated := configPgOptional.Set(PostgreSQL{Host: "remote"})(config)
// updated.Database.Connection = PostgreSQL{Host: "remote"}

configMySQL := Config{Database: DatabaseConfig{Connection: MySQL{Host: "localhost"}}}
none := configPgOptional.GetOption(configMySQL)  // None (Prism doesn't match)
unchanged := configPgOptional.Set(PostgreSQL{Host: "remote"})(configMySQL)
// unchanged == configMySQL (no-op because Prism doesn't match)

func LensComposePrismRef added in v2.3.122

func LensComposePrismRef[S, A, B any](p Prism[A, B]) func(Lens[*S, A]) Optional[*S, B]

LensComposePrismRef composes a Lens operating on pointer types with a Prism to create an Optional.

This is the pointer-safe variant of Compose, designed for working with pointer types (*S). It automatically handles nil pointer cases and creates copies before modification to ensure immutability and prevent unintended side effects.

The composition follows the same Optional laws as Compose:

SetGet Law (GetSet for Optional):

  • If optional.GetOption(s) = Some(b), then optional.GetOption(optional.Set(b)(s)) = Some(b)
  • This ensures that setting a value and then getting it returns the same value

GetSet Law (for Optional):

  • If optional.GetOption(s) = None, then optional.Set(b)(s) = s (no-op)
  • This ensures that setting a value when the optional doesn't match leaves the structure unchanged

Nil Pointer Handling:

  • When s is nil and GetOption would return None, Set operations return nil (no-op)
  • When s is nil and GetOption would return Some (after creating default), Set creates a new instance
  • All Set operations create a shallow copy of *S before modification to preserve immutability

These laws are documented in the official fp-ts documentation: https://gcanti.github.io/monocle-ts/modules/Optional.ts.html

Type Parameters:

  • S: The source/outer structure type (used as *S in the lens)
  • A: The intermediate type (focused by the Lens)
  • B: The target type (focused by the Prism within A)

Parameters:

  • p: A Prism[A, B] that optionally extracts B from A

Returns:

  • A function that takes a Lens[*S, A] and returns an Optional[*S, B]

Behavior:

  • GetOption: First uses the Lens to get A from *S, then uses the Prism to try to extract B from A. Returns Some(b) if both operations succeed, None otherwise.
  • Set: When setting a value b:
  • Creates a shallow copy of *S before any modification (nil-safe)
  • If GetOption(s) returns Some(_), it means the Prism matches, so we: 1. Use Prism.ReverseGet to construct an A from b 2. Use Lens.Set to update the copy of *S with the new A
  • If GetOption(s) returns None, the Prism doesn't match, so we return s unchanged (no-op)

Example:

type Config struct {
    Connection ConnectionType
    AppName    string
}

type ConnectionType interface{ isConnection() }
type PostgreSQL struct{ Host string }
type MySQL struct{ Host string }

// Lens to focus on Connection field (pointer-based)
connLens := lens.MakeLensRef(
    func(c *Config) ConnectionType { return c.Connection },
    func(c *Config, ct ConnectionType) *Config { c.Connection = ct; return c },
)

// Prism to extract PostgreSQL from ConnectionType
pgPrism := prism.MakePrism(
    func(ct ConnectionType) OptionOption[PostgreSQL] {
        if pg, ok := ct.(PostgreSQL); ok {
            return OptionSome(pg)
        }
        return OptionNone[PostgreSQL]()
    },
    func(pg PostgreSQL) ConnectionType { return pg },
)

// Compose to create Optional[*Config, PostgreSQL]
configPgOptional := LensComposePrismRef[Config, ConnectionType, PostgreSQL](pgPrism)(connLens)

// Works with non-nil pointers
config := &Config{Connection: PostgreSQL{Host: "localhost"}}
host := configPgOptional.GetOption(config)  // Some(PostgreSQL{Host: "localhost"})
updated := configPgOptional.Set(PostgreSQL{Host: "remote"})(config)
// updated is a new *Config with Connection = PostgreSQL{Host: "remote"}
// original config is unchanged (immutability preserved)

// Handles nil pointers safely
var nilConfig *Config = nil
none := configPgOptional.GetOption(nilConfig)  // None (nil pointer)
unchanged := configPgOptional.Set(PostgreSQL{Host: "remote"})(nilConfig)
// unchanged == nil (no-op because source is nil)

// Works with mismatched prisms
configMySQL := &Config{Connection: MySQL{Host: "localhost"}}
none = configPgOptional.GetOption(configMySQL)  // None (Prism doesn't match)
unchanged = configPgOptional.Set(PostgreSQL{Host: "remote"})(configMySQL)
// unchanged == configMySQL (no-op because Prism doesn't match)

func LensModify

func LensModify[S any, FCT ~func(A) A, A any](f FCT) func(Lens[S, A]) Endomorphism[S]

LensModify transforms a value through a lens using a transformation F.

Instead of setting a specific value, LensModify applies a function to the current value. This is useful for updates like incrementing a counter, appending to a string, etc. If the transformation doesn't change the value, the original structure is returned.

Type Parameters:

  • S: Structure type
  • FCT: Transformation function type (A → A)
  • A: Focus type

Parameters:

  • f: Transformation function to apply to the focused value

Returns:

  • A function that takes a Lens[S, A] and returns an Endomorphism[S]

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 },
)

counter := Counter{Value: 5}

// Increment the counter
incremented := F.Pipe2(
    valueLens,
    lens.LensModify[Counter](func(v int) int { return v + 1 }),
    F.Ap(counter),
)
// incremented.Value == 6

// Double the counter
doubled := F.Pipe2(
    valueLens,
    lens.LensModify[Counter](func(v int) int { return v * 2 }),
    F.Ap(counter),
)
// doubled.Value == 10

func LensModifyF

func LensModifyF[S, A, HKTA, HKTS any](
	fmap functor.MapType[A, S, HKTA, HKTS],
) func(func(A) HKTA) func(Lens[S, A]) func(S) HKTS

LensModifyF transforms a value through a lens using a function that returns a value in a functor context.

This is the functorial version of Modify, allowing transformations that produce effects (like Option, Either, IO, etc.) while updating the focused value. The functor's map operation is used to apply the lens's setter to the transformed value, preserving the computational context.

This function corresponds to modifyF from monocle-ts, enabling effectful updates through lenses.

Type Parameters

  • S: Structure type
  • A: Focus type (the value being transformed)
  • HKTA: Higher-kinded type containing the transformed value (e.g., Option[A], Either[E, A])
  • HKTS: Higher-kinded type containing the updated structure (e.g., Option[S], Either[E, S])

Parameters

  • fmap: A functor map operation that transforms A to S within the functor context

Returns

  • A curried function that takes: 1. A transformation function (A → HKTA) 2. A Lens[S, A] 3. A structure S And returns the updated structure in the functor context (HKTS)

Example Usage

type Person struct {
    Name string
    Age  int
}

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

// Validate age is positive, returning Option
validateAge := func(age int) option.Option[int] {
    if age > 0 {
        return option.Some(age)
    }
    return option.None[int]()
}

// Create a modifier that validates while updating
modifyAge := lens.LensModifyF[Person, int](option.Functor[int, Person]().Map)

person := Person{Name: "Alice", Age: 30}
result := modifyAge(validateAge)(ageLens)(person)
// result is Some(Person{Name: "Alice", Age: 30})

invalidResult := modifyAge(func(age int) option.Option[int] {
    return option.None[int]()
})(ageLens)(person)
// invalidResult is None[Person]()

See Also

  • Modify: Non-functorial version for simple transformations
  • functor.Functor: The functor interface used for mapping

func LensSet

func LensSet[S any, A any](a A) func(Lens[S, A]) Endomorphism[S]

LensSet returns a function that updates the focus of a lens to a constant value.

This is a convenience helper for partially applying a value before supplying the lens, making it useful in composition pipelines with F.Pipe.

Example:

type Counter struct {
    Value int
}

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

counter := Counter{Value: 5}
updated := F.Pipe2(
    10,
    lens.LensSet[Counter](10),
    F.Ap(valueLens),
)
// updated.Value == 10

func OptionCompactArray added in v2.3.120

func OptionCompactArray[A any](fa []Option[A]) []A

OptionCompactArray filters an array of Options, keeping only the Some values and discarding None values.

Example:

input := A.From(OptionSome(1), OptionNone[int](), OptionSome(3), OptionSome(5), OptionNone[int]())
result := OptionCompactArray(input) // [1, 3, 5]

func OptionCompactArrayG added in v2.3.120

func OptionCompactArrayG[A1 ~[]Option[A], A2 ~[]A, A any](fa A1) A2

OptionCompactArrayG filters an array of Options, keeping only the Some values and discarding None values. This is the generic version that works with custom slice types.

Example:

type MySlice []int
input := A.From(OptionSome(1), OptionNone[int](), OptionSome(3))
result := OptionCompactArrayG[[]Option[int], MySlice](input) // MySlice{1, 3}

func OptionFold added in v2.3.120

func OptionFold[A, B any](onNone func() B, onSome func(a A) B) func(Option[A]) B

OptionFold provides a way to handle both Some and None cases of an Option. Returns a function that applies onNone if the Option is None, or onSome if it is Some.

Example:

handler := OptionFold(
    func() string { return "no value" },
    func(x int) string { return fmt.Sprintf("value: %d", x) },
)
result := handler(OptionSome(42))    // "value: 42"
result := handler(OptionNone[int]()) // "no value"

Relation to predicate.OptionFold:

option.OptionFold and predicate.OptionFold are two specialisations of the same categorical pattern — eliminating a two-case sum type into a common result type B.

option.Option[A] is a two-case sum type {None, OptionSome(A)}. The Some constructor carries a payload of type A, so the onSome branch receives it; the None branch carries no payload and is therefore a thunk:

option.OptionFold :: (() → B) → (A → B) → Option[A] → B

predicate.Predicate[A] is morally equivalent to A → bool, where bool is the smallest two-case sum type {false, true}. Because bool carries no payload beyond the branch tag, both handlers in predicate.OptionFold must receive A to preserve context:

predicate.OptionFold :: (A → B) → (A → B) → (A → bool) → A → B

The link between the two is FromPredicate, which converts a Predicate[A] into an Option[A]-producing function. Using it, predicate.OptionFold can always be expressed in terms of option.OptionFold:

predicate.OptionFold(onFalse, onTrue)(p)(a)
  == option.OptionFold(func() B { return onFalse(a) }, onTrue)(FromPredicate(p)(a))

Conversely, option.OptionFold cannot in general be expressed via predicate.OptionFold because None carries no A value for the false branch to inspect.

See Also:

  • MonadFold: The uncurried form of this function
  • predicate.OptionFold: The analogous eliminator for the bool two-case sum type
  • FromPredicate: Converts a Predicate[A] into a OptionKleisli[A, A] producing Option[A]

func OptionFromEq added in v2.3.120

func OptionFromEq[A any](pred eq.Eq[A]) func(A) OptionKleisli[A, A]

func OptionFromStrictEq added in v2.3.120

func OptionFromStrictEq[A comparable]() func(A) OptionKleisli[A, A]

func OptionGetOrElse added in v2.3.120

func OptionGetOrElse[A any](onNone func() A) func(Option[A]) A

OptionGetOrElse returns a function that extracts the value from an Option or returns a default.

Example:

getOrZero := OptionGetOrElse(lazy.Of(0))
result := getOrZero(OptionSome(42)) // 42
result := getOrZero(OptionNone[int]()) // 0

func OptionIsNone added in v2.3.120

func OptionIsNone[T any](val Option[T]) bool

OptionIsNone checks if an Option is None (contains no value).

Example:

opt := OptionNone[int]()
OptionIsNone(opt) // true
opt := OptionSome(42)
OptionIsNone(opt) // false

func OptionIsSome added in v2.3.120

func OptionIsSome[T any](val Option[T]) bool

OptionIsSome checks if an Option contains a value.

Example:

opt := OptionSome(42)
OptionIsSome(opt) // true
opt := OptionNone[int]()
OptionIsSome(opt) // false

func OptionMonadFold added in v2.3.120

func OptionMonadFold[A, B any](ma Option[A], onNone func() B, onSome func(A) B) B

OptionMonadFold performs a fold operation on an Option. If the Option is Some, applies onSome to the value. If the Option is None, calls onNone.

Example:

opt := OptionSome(42)
result := OptionMonadFold(opt,
    func() string { return "no value" },
    func(x int) string { return fmt.Sprintf("value: %d", x) },
) // "value: 42"

func OptionMonadGetOrElse added in v2.3.120

func OptionMonadGetOrElse[A any](fa Option[A], onNone func() A) A

OptionMonadGetOrElse extracts the value from an Option or returns a default value. This is the monadic form of GetOrElse.

Example:

result := OptionMonadGetOrElse(OptionSome(42), lazy.Of(0)) // 42
result := OptionMonadGetOrElse(OptionNone[int](), lazy.Of(0)) // 0

func OptionReduce added in v2.3.120

func OptionReduce[A, B any](f func(B, A) B, initial B) func(Option[A]) B

OptionReduce folds an Option into a single value using a reducer function. If the Option is None, returns the initial value.

Example:

sum := OptionReduce(func(acc, val int) int { return acc + val }, 0)
result := sum(OptionSome(5)) // 5
result := sum(OptionNone[int]()) // 0

func OptionSequence2 added in v2.3.120

func OptionSequence2[T1, T2, R any](f func(T1, T2) Option[R]) func(Option[T1], Option[T2]) Option[R]

OptionSequence2 returns a function that sequences two Options with a combining function.

Example:

add := OptionSequence2(func(a, b int) Option[int] { return OptionSome(a + b) })
result := add(OptionSome(2), OptionSome(3)) // OptionSome(5)

func OptionToNillable2 added in v2.3.120

func OptionToNillable2[A any](fa Option[A]) *A

OptionToNillable2 converts an Option[A] back to a nullable pointer. Returns a pointer to the contained value when the Option is Some, nil otherwise. This is the inverse of FromNillable2: round-tripping through both functions preserves the value but allocates a new pointer on each call.

Type Parameters:

  • A: the type contained in the Option

Parameters:

  • fa: the Option value to convert

Returns:

  • a pointer to a copy of the contained value when fa is Some
  • nil when fa is None

See Also:

  • FromNillable2: the inverse — converts *A to Option[A]

func OptionUnwrap added in v2.3.120

func OptionUnwrap[A any](ma Option[A]) (A, bool)

OptionUnwrap extracts the value and presence flag from an Option. Returns the value and true if Some, or zero value and false if None.

Example:

opt := OptionSome(42)
val, ok := OptionUnwrap(opt) // val = 42, ok = true
opt := OptionNone[int]()
val, ok := OptionUnwrap(opt) // val = 0, ok = false

func OptionalAsTraversal

func OptionalAsTraversal[R ~func(func(A) HKTA) func(S) HKTS, S, A, HKTS, HKTA any](
	fof pointed.OfType[S, HKTS],
	fmap functor.MapType[A, S, HKTA, HKTS],
) func(Optional[S, A]) R

func OptionalFromPredicate

func OptionalFromPredicate[S, A any](pred func(A) bool) func(func(S) A, func(S, A) S) Optional[S, A]

OptionalFromPredicate creates an optional from getter and setter functions. It checks for optional values and the correct update procedure

func OptionalFromPredicateRef

func OptionalFromPredicateRef[S, A any](pred func(A) bool) func(func(*S) A, func(*S, A) *S) Optional[*S, A]

FromPredicate creates an optional from getter and setter functions. It checks for optional values and the correct update procedure

func OptionalModifyOption

func OptionalModifyOption[S, A any](f func(A) A) func(Optional[S, A]) OptionKleisli[S, S]

func OptionalSetOption

func OptionalSetOption[S, A any](a A) func(Optional[S, A]) OptionKleisli[S, S]

func PrismAsTraversal

func PrismAsTraversal[R ~func(func(A) HKTA) func(S) HKTS, S, A, HKTS, HKTA any](
	fof pointed.OfType[S, HKTS],
	fmap functor.MapType[A, S, HKTA, HKTS],
) func(Prism[S, A]) R

PrismAsTraversal converts a Prism into a Traversal.

A Traversal is a more general optic that can focus on zero or more values, while a Prism focuses on zero or one value. This function lifts a Prism into the Traversal abstraction, allowing it to be used in contexts that expect traversals.

The conversion works by:

  • If the prism matches (GetOption returns Some), the traversal focuses on that value
  • If the prism doesn't match (GetOption returns None), the traversal focuses on zero values

Type Parameters:

  • R: The traversal function type ~func(func(A) HKTA) func(S) HKTS
  • S: The source type
  • A: The focus type
  • HKTS: Higher-kinded type for S (e.g., functor/applicative context)
  • HKTA: Higher-kinded type for A (e.g., functor/applicative context)

Parameters:

  • fof: Function to lift S into the higher-kinded type HKTS (pure/of operation)
  • fmap: Function to map over HKTA and produce HKTS (functor map operation)

Returns:

  • A function that converts a Prism[S, A] into a Traversal R

Example:

// Convert a prism to a traversal for use with applicative functors
prism := MakePrism(...)
traversal := AsTraversal(
    func(s S) HKTS { return pure(s) },
    func(hkta HKTA, f func(A) S) HKTS { return fmap(hkta, f) },
)(prism)

Note: This function is typically used in advanced scenarios involving higher-kinded types and applicative functors. Most users will work directly with prisms rather than converting them to traversals.

func PrismSet

func PrismSet[S, A any](a A) func(Prism[S, A]) Endomorphism[S]

PrismSet creates a function that sets a value through a prism. If the prism matches, it replaces the focused value with the new value. If the prism doesn't match, it returns the original value unchanged.

Parameters:

  • a: The new value to set

Returns:

  • A function that takes a prism and returns an endomorphism (S → S)

Example:

somePrism := MakePrism(...)
setter := PrismSet[Option[int], int](100)
result := setter(somePrism)(Some(42))  // Some(100)
result = setter(somePrism)(None[int]()) // None[int]() (unchanged)

Types

type Either added in v2.3.122

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

func EitherFlatten added in v2.3.122

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

EitherFlatten removes one level of nesting from a nested Either.

Example:

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

func EitherFromIO added in v2.3.122

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

EitherFromIO 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 := lazy.Of(42)
result := either.EitherFromIO[error](getValue) // Right(42)

go: inline

func EitherLeft added in v2.3.122

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

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

Example:

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

func EitherMemoize added in v2.3.122

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

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

func EitherMonadAlt added in v2.3.122

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

EitherMonadAlt provides an alternative Either if the first is Left. This is the monadic version of EitherAlt.

func EitherMonadAp added in v2.3.122

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

EitherMonadAp 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.EitherRight[error](N.Mul(2))
fa := either.EitherRight[error](21)
result := either.EitherMonadAp(fab, fa) // Right(42)

func EitherMonadBiMap added in v2.3.122

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

EitherMonadBiMap 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.EitherMonadBiMap(
    either.EitherLeft[int](errors.New("error")),
    error.Error,
    func(n int) string { return fmt.Sprint(n) },
) // Left("error")

func EitherMonadChain added in v2.3.122

func EitherMonadChain[E, A, B any](fa Either[E, A], f EitherKleisli[E, A, B]) Either[E, B]

EitherMonadChain 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.EitherMonadChain(
    either.EitherRight[error](21),
    func(x int) either.Either[error, int] {
        return either.EitherRight[error](x * 2)
    },
) // Right(42)

func EitherMonadChainFirst added in v2.3.122

func EitherMonadChainFirst[E, A, B any](ma Either[E, A], f EitherKleisli[E, A, B]) Either[E, A]

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

Example:

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

func EitherMonadChainLeft added in v2.3.122

func EitherMonadChainLeft[EA, EB, A any](fa Either[EA, A], f EitherKleisli[EB, EA, A]) Either[EB, A]

EitherMonadChainLeft sequences a computation on the Left (error) value, allowing error recovery or transformation. If the Either is Left, applies the provided function to the error value, which returns a new Either. If the Either is Right, returns the Right value unchanged with the new error type.

This is the dual of EitherMonadChain - while EitherMonadChain operates on Right values (success), EitherMonadChainLeft operates on Left values (errors). It's useful for error recovery, error transformation, or chaining alternative computations when an error occurs.

Note: EitherMonadChainLeft is identical to EitherOrElse - both provide the same functionality for error recovery.

The error type can be transformed from EA to EB, allowing flexible error type conversions.

Example:

// Error recovery: convert specific errors to success
result := either.EitherMonadChainLeft(
    either.EitherLeft[int](errors.New("not found")),
    func(err error) either.Either[string, int] {
        if err.Error() == "not found" {
            return either.EitherRight[string](0) // default value
        }
        return either.EitherLeft[int](err.Error()) // transform error
    },
) // Right(0)

// Error transformation: change error type
result := either.EitherMonadChainLeft(
    either.EitherLeft[int](404),
    func(code int) either.Either[string, int] {
        return either.EitherLeft[int](fmt.Sprintf("Error code: %d", code))
    },
) // Left("Error code: 404")

// Right values pass through unchanged
result := either.EitherMonadChainLeft(
    either.EitherRight[error](42),
    func(err error) either.Either[string, int] {
        return either.EitherLeft[int]("error")
    },
) // Right(42)

func EitherMonadChainOptionK added in v2.3.122

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

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

Example:

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

func EitherMonadChainTo added in v2.3.122

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

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

func EitherMonadExtend added in v2.3.122

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

EitherMonadExtend applies a function to an Either value, where the function receives the entire Either as input. This is the Extend (or Comonad) operation that allows computations to depend on the context.

If the Either is Left, it returns Left unchanged without applying the function. If the Either is Right, it applies the function to the entire Either and wraps the result in a Right.

This operation is useful when you need to perform computations that depend on whether a value is present (Right) or absent (Left), not just on the value itself.

Type Parameters:

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

Parameters:

  • fa: The Either value to extend
  • f: Function that takes the entire Either[E, A] and produces a value of type B

Returns:

  • Either[E, B]: Left if input was Left, otherwise Right containing the result of f(fa)

Example:

// Count how many times we've seen a Right value
counter := func(e either.Either[error, int]) int {
    return either.Fold(
        func(err error) int { return 0 },
        func(n int) int { return 1 },
    )(e)
}
result := either.EitherMonadExtend(either.Right[error](42), counter) // Right(1)
result := either.EitherMonadExtend(either.Left[int](errors.New("err")), counter) // Left(error)

func EitherMonadFlap added in v2.3.122

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

EitherMonadFlap applies a value to a function wrapped in Either. This is the reverse of EitherMonadAp.

func EitherMonadMap added in v2.3.122

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

EitherMonadMap 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.EitherMonadMap(
    either.EitherRight[error](21),
    N.Mul(2),
) // Right(42)

func EitherMonadMapLeft added in v2.3.122

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

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

Example:

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

func EitherMonadMapTo added in v2.3.122

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

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

Example:

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

func EitherMonadSequence2 added in v2.3.122

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

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

func EitherMonadSequence3 added in v2.3.122

func EitherMonadSequence3[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]

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

func EitherOf added in v2.3.122

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

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

Example:

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

func EitherRight added in v2.3.122

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

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

Example:

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

func EitherSequenceArray added in v2.3.122

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

EitherSequenceArray 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 := A.From(
    either.Right[error](1),
    either.Right[error](2),
    either.Right[error](3),
)
result := either.EitherSequenceArray(eithers)
// result is Right([]int{1, 2, 3})

func EitherSequenceArrayG added in v2.3.122

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

func EitherSequenceRecord added in v2.3.122

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

EitherSequenceRecord 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.EitherSequenceRecord(eithers)
// result is Right(map[string]int{"a": 1, "b": 2})

func EitherSequenceRecordG added in v2.3.122

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

func EitherSequenceSeq added in v2.3.122

func EitherSequenceSeq[E, A any](ma iter.Seq[Either[E, A]]) Either[E, iter.Seq[A]]

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

This function eagerly evaluates all Either values in the input iterator to detect any Left values, then returns an iterator over the collected Right values.

Type Parameters

  • E: The error type for Left values
  • A: The value type for Right values

Parameters

  • ma: An iterator of Either values

Returns

  • Either containing an iterator of Right values, or the first Left encountered

Example Usage

eithers := slices.Values([]either.Either[error, int]{
    either.Right[error](1),
    either.Right[error](2),
    either.Right[error](3),
})
result := either.SequenceSeq(eithers)
// result is Right(iterator over [1, 2, 3])

See Also

  • EitherSequenceArray: For slice-based sequencing
  • EitherTraverseSeq: For transforming and sequencing in one step

func EitherSwap added in v2.3.122

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

EitherSwap exchanges the Left and Right type parameters.

Example:

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

func EitherTryCatch added in v2.3.122

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

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

Example:

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

func EitherTryCatchError added in v2.3.122

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

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

Example:

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

func EitherZero added in v2.3.122

func EitherZero[E, A any]() Either[E, A]

EitherZero returns the zero value of an Either, which is a Right containing the zero value of type A. This function is useful as an identity element in monoid operations or for creating an empty Either in a Right state.

The returned Either is always a Right value containing the zero value of type A. For reference types (pointers, slices, maps, channels, functions, interfaces), the zero value is nil. For value types (numbers, booleans, structs), it's the type's zero value.

Important: EitherZero() returns the same value as the default initialization of Either[E, A]. When you declare `var e Either[E, A]` without initialization, it has the same value as EitherZero[E, A]().

Note: This differs from creating a Left value, which would represent an error or failure state. EitherZero always produces a successful (Right) state with a zero value.

Example:

// Zero Either with int value
e1 := either.EitherZero[error, int]()  // Right(0)

// Zero Either with string value
e2 := either.EitherZero[error, string]()  // Right("")

// Zero Either with pointer type
e3 := either.EitherZero[error, *int]()  // Right(nil)

// Zero equals default initialization
var defaultInit Either[error, int]
zero := either.EitherZero[error, int]()
assert.Equal(t, defaultInit, zero) // true

// Verify it's a Right value
e := either.EitherZero[error, int]()
assert.True(t, either.IsRight(e))  // true
assert.False(t, either.IsLeft(e))  // false

func (Either[E, A]) Format added in v2.3.122

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, %q, and all other verbs: uses String() representation

The exact output format is not a stable contract and may change across versions.

func (Either[E, A]) LogValue added in v2.3.122

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

func (Either[E, A]) String added in v2.3.122

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

String implements fmt.Stringer for Either. Returns a human-readable string representation intended for debugging and logging. The exact format is not a stable contract and may change across versions.

type EitherKleisli added in v2.3.122

type EitherKleisli[E, A, B any] = func(A) Either[E, B]

EitherKleisli represents a Kleisli arrow for the Either monad. It's a function from A to Either[E, B], used for composing operations that may fail.

func EitherAltAllArray added in v2.3.122

func EitherAltAllArray[E, A any](startWith Either[E, A]) EitherKleisli[E, []Either[E, A], A]

EitherAltAllArray combines multiple Either values from an array using the Alt operation. It starts with an initial Either and iteratively applies Alt with each Either in the array, returning the first Right value encountered or the last Left value if all are Left.

The Alt operation returns the first Either if it's Right, otherwise returns the alternative. This function chains multiple Alt operations together, effectively implementing a "first success" or "fallback chain" pattern for Either values.

Implementation:

This function is semantically equivalent to alt.AltAllArray[Either[E, A]](Alt)(startWith) but uses the generic implementation directly. The generic alt.AltAllArray provides lazy evaluation through thunks, which enables early break when a Right value is found.

Short-Circuit Behavior:

This function short-circuits on the first Right value but processes all Left values:

  • If startWith is Right, it returns immediately without examining the array
  • When iterating, it returns immediately upon finding the first Right value
  • The array is not fully consumed once a Right value is found
  • If all elements are Left, the entire array is traversed and the last Left is returned

Relationship to array.Fold and AltMonoid:

EitherAltAllArray is closely related to array.Fold with AltMonoid:

  • When startWith is Left, EitherAltAllArray(Left[E, A](e))(eithers) is equivalent to array.Fold(AltMonoid[E, A]())(eithers)
  • When startWith is Right, it's equivalent to prepending startWith to the array before folding: array.Fold(AltMonoid[E, A]())(append([]Either[E, A]{startWith}, eithers...))
  • AltMonoid is a monoid that uses Alt as its Concat operation and Left as Empty
  • Both approaches have O(n) time complexity and similar performance

Use EitherAltAllArray when you want to:

  • Express the "find first Right value" pattern clearly
  • Specify a custom starting value (not just Left)
  • Work specifically with Either values in a functional style
  • Implement fallback chains for error handling

Type Parameters:

  • E: The type of error/Left value
  • A: The type of success/Right value

Parameters:

  • startWith: The initial Either to start the chain with

Returns:

  • Kleisli[E, []Either[E, A], A]: A function that takes an array of Either values and returns an Either containing the first Right value, or the last Left value if all are Left

See Also:

  • Alt: The underlying Alt operation
  • EitherAltAllSeq: Similar function for iterator sequences
  • AltMonoid: Monoid that uses Alt operation

func EitherAltAllSeq added in v2.3.122

func EitherAltAllSeq[E, A any](startWith Either[E, A]) EitherKleisli[E, iter.Seq[Either[E, A]], A]

EitherAltAllSeq combines multiple Either values from an iterator sequence using the Alt operation. It starts with an initial Either and iteratively applies Alt with each Either from the sequence, returning the first Right value encountered or the last Left value if all are Left.

This function is similar to EitherAltAllArray but works with Go's iterator sequences, making it suitable for lazy evaluation and potentially infinite sequences.

Implementation:

This function is semantically equivalent to alt.AltAllSeq[Either[E, A]](Alt)(startWith) but uses the generic implementation directly. The generic alt.AltAllSeq provides lazy evaluation through thunks, which enables early break when a Right value is found.

Short-Circuit Behavior:

This function short-circuits on the first Right value but processes all Left values:

  • If startWith is Right, it returns immediately without consuming the sequence
  • When iterating, it returns immediately upon finding the first Right value
  • The sequence is not fully consumed once a Right value is found
  • This makes it safe to use with infinite sequences as long as a Right value exists
  • If all elements are Left, the entire sequence is consumed and the last Left is returned

Relationship to Folding:

Like EitherAltAllArray, this function implements a fold operation using the Alt operation. The key difference is that it works with iterator sequences instead of arrays, enabling:

  • Lazy evaluation of the sequence
  • Working with potentially infinite sequences
  • Memory-efficient processing of large datasets
  • Composition with other iterator-based operations

The relationship to AltMonoid is the same as EitherAltAllArray, but applied to sequences rather than arrays.

Type Parameters:

  • E: The type of error/Left value
  • A: The type of success/Right value

Parameters:

  • startWith: The initial Either to start the chain with

Returns:

  • EitherKleisli[E, iter.Seq[Either[E, A]], A]: A function that takes a sequence of Either values and returns an Either containing the first Right value, or the last Left value if all are Left

See Also:

  • Alt: The underlying Alt operation
  • EitherAltAllArray: Similar function for arrays
  • AltMonoid: Monoid that uses Alt operation

func EitherAltW added in v2.3.122

func EitherAltW[E, E1, A any](that func() Either[E1, A]) EitherKleisli[E1, Either[E, A], A]

EitherAltW 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.EitherAltW[error, string](func() either.Either[string, int] {
    return either.EitherRight[string](99)
})
result := alternative(either.EitherLeft[int](errors.New("fail"))) // Right(99)

func EitherChainLeft added in v2.3.122

func EitherChainLeft[EA, EB, A any](f EitherKleisli[EB, EA, A]) EitherKleisli[EB, Either[EA, A], A]

EitherChainLeft is the curried version of EitherMonadChainLeft. Returns a function that sequences a computation on the Left (error) value.

Note: EitherChainLeft is identical to EitherOrElse - both provide the same functionality for error recovery.

This is useful for creating reusable error handlers or transformers that can be composed with other Either operations using pipes or function composition.

Example:

// Create a reusable error handler
handleNotFound := either.EitherChainLeft[error, string](func(err error) either.Either[string, int] {
    if err.Error() == "not found" {
        return either.EitherRight[string](0)
    }
    return either.EitherLeft[int](err.Error())
})

// Use in a pipeline
result := F.Pipe1(
    either.EitherLeft[int](errors.New("not found")),
    handleNotFound,
) // Right(0)

func EitherFromNillable added in v2.3.122

func EitherFromNillable[A, E any](e E) EitherKleisli[E, *A, *A]

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

Example:

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

func EitherFromPredicate added in v2.3.122

func EitherFromPredicate[E, A any](pred Predicate[A], onFalse func(A) E) EitherKleisli[E, A, A]

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

Example:

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

func EitherOrElse added in v2.3.122

func EitherOrElse[E1, E2, A any](onLeft EitherKleisli[E2, E1, A]) EitherKleisli[E2, Either[E1, A], A]

EitherOrElse recovers from a Left (error) by providing an alternative computation. If the Either is Right, it returns the value unchanged. If the Either is Left, it applies the provided function to the error value, which returns a new Either that replaces the original.

Note: EitherOrElse is identical to EitherChainLeft - both provide the same functionality for error recovery.

This is useful for error recovery, fallback logic, or chaining alternative computations. The error type can be widened from E1 to E2, allowing transformation of error types.

Example:

// Recover from specific errors with fallback values
recover := either.EitherOrElse(func(err error) either.Either[error, int] {
    if err.Error() == "not found" {
        return either.EitherRight[error](0) // default value
    }
    return either.EitherLeft[int](err) // propagate other errors
})
result := recover(either.EitherLeft[int](errors.New("not found"))) // Right(0)
result := recover(either.EitherRight[error](42)) // Right(42) - unchanged

func EitherTraverseArray added in v2.3.122

func EitherTraverseArray[E, A, B any](f EitherKleisli[E, A, B]) EitherKleisli[E, []A, []B]

EitherTraverseArray 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.EitherTraverseArray(parse)([]string{"1", "2", "3"})
// result is Right([]int{1, 2, 3})

func EitherTraverseArrayG added in v2.3.122

func EitherTraverseArrayG[GA ~[]A, GB ~[]B, E, A, B any](f EitherKleisli[E, A, B]) EitherKleisli[E, GA, GB]

EitherTraverseArrayG 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.EitherTraverseArrayG[[]string, []int](parse)([]string{"1", "2", "3"})
// result is Right([]int{1, 2, 3})

func EitherTraverseArrayWithIndex added in v2.3.122

func EitherTraverseArrayWithIndex[E, A, B any](f func(int, A) Either[E, B]) EitherKleisli[E, []A, []B]

EitherTraverseArrayWithIndex 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.EitherTraverseArrayWithIndex(validate)([]string{"a", "b"})
// result is Right([]string{"0:a", "1:b"})

func EitherTraverseArrayWithIndexG added in v2.3.122

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

EitherTraverseArrayWithIndexG 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.EitherTraverseArrayWithIndexG[[]string, []string](validate)([]string{"a", "b"})
// result is Right([]string{"0:a", "1:b"})

func EitherTraverseRecord added in v2.3.122

func EitherTraverseRecord[K comparable, E, A, B any](f EitherKleisli[E, A, B]) EitherKleisli[E, map[K]A, map[K]B]

EitherTraverseRecord 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.EitherTraverseRecord[string](parse)(map[string]string{"a": "1", "b": "2"})
// result is Right(map[string]int{"a": 1, "b": 2})

func EitherTraverseRecordG added in v2.3.122

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

EitherTraverseRecordG 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.EitherTraverseRecordG[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 EitherTraverseRecordWithIndex added in v2.3.122

func EitherTraverseRecordWithIndex[K comparable, E, A, B any](f func(K, A) Either[E, B]) EitherKleisli[E, map[K]A, map[K]B]

EitherTraverseRecordWithIndex 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.EitherTraverseRecordWithIndex[string](validate)(map[string]string{"a": "1"})
// result is Right(map[string]string{"a": "a:1"})

func EitherTraverseRecordWithIndexG added in v2.3.122

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

EitherTraverseRecordWithIndexG 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.EitherTraverseRecordWithIndexG[map[string]string, map[string]string](validate)(map[string]string{"a": "1"})
// result is Right(map[string]string{"a": "a:1"})

func EitherTraverseSeq added in v2.3.122

func EitherTraverseSeq[E, A, B any](f EitherKleisli[E, A, B]) EitherKleisli[E, iter.Seq[A], iter.Seq[B]]

TraverseSeq transforms an iterator 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 an iterator of all Right values.

The function eagerly evaluates all elements in the input iterator to detect any Left values, then returns an iterator over the collected Right values. This is necessary because Either represents computations that can fail, and we need to know if any element failed before producing the result iterator.

Type Parameters

  • E: The error type for Left values
  • A: The input element type
  • B: The output element type

Parameters

  • f: A function that transforms each element into an Either

Returns

  • A function that takes an iterator of A and returns Either containing an iterator of B

Example Usage

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

See Also

  • EitherTraverseArray: For slice-based traversal
  • EitherSequenceSeq: For sequencing iterators of Either values

func EitherWithResource added in v2.3.122

func EitherWithResource[A, E, R, ANY any](
	onCreate func() Either[E, R],
	onRelease EitherKleisli[E, R, ANY],
) EitherKleisli[E, EitherKleisli[E, R, A], A]

EitherWithResource 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.EitherWithResource(
    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 EitherOperator added in v2.3.122

type EitherOperator[E, A, B any] = EitherKleisli[E, Either[E, A], B]

EitherOperator represents a function that transforms one Either into another. It takes an Either[E, A] and produces an Either[E, B].

func EitherAlt added in v2.3.122

func EitherAlt[E, A any](that func() Either[E, A]) EitherOperator[E, A, A]

EitherAlt provides an alternative Either if the first is Left.

Example:

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

func EitherAp added in v2.3.122

func EitherAp[B, E, A any](fa Either[E, A]) EitherOperator[E, func(A) B, B]

EitherAp is the curried version of EitherMonadAp. Returns a function that applies a wrapped function to the given wrapped value.

func EitherChain added in v2.3.122

func EitherChain[E, A, B any](f EitherKleisli[E, A, B]) EitherOperator[E, A, B]

EitherChain is the curried version of EitherMonadChain. Sequences two computations where the second depends on the first.

func EitherChainFirst added in v2.3.122

func EitherChainFirst[E, A, B any](f EitherKleisli[E, A, B]) EitherOperator[E, A, A]

EitherChainFirst is the curried version of EitherMonadChainFirst.

func EitherChainTo added in v2.3.122

func EitherChainTo[A, E, B any](mb Either[E, B]) EitherOperator[E, A, B]

EitherChainTo is the curried version of EitherMonadChainTo.

func EitherExtend added in v2.3.122

func EitherExtend[E, A, B any](f func(Either[E, A]) B) EitherOperator[E, A, B]

EitherExtend is the curried version of EitherMonadExtend. It returns a function that applies the given function to an Either value.

This is useful for creating reusable transformations that depend on the Either context.

Type Parameters:

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

Parameters:

  • f: Function that takes the entire Either[E, A] and produces a value of type B

Returns:

  • Operator[E, A, B]: A function that transforms Either[E, A] to Either[E, B]

Example:

// Create a reusable extender that extracts metadata
getMetadata := either.EitherExtend(func(e either.Either[error, string]) string {
    return either.Fold(
        func(err error) string { return "error: " + err.Error() },
        func(s string) string { return "value: " + s },
    )(e)
})
result := getMetadata(either.Right[error]("hello")) // Right("value: hello")

func EitherFilter added in v2.3.122

func EitherFilter[E, A any](p Predicate[A], empty E) EitherOperator[E, A, A]

EitherFilter creates a filtering operation for Either values based on a predicate function. It returns a function that takes an Either and produces an Either, where Right values that fail the predicate are converted to Left values with the provided empty value.

This function implements the Filterable specification's filter operation: https://github.com/fantasyland/fantasy-land#filterable

The behavior is as follows:

  • If the input is Left, it passes through unchanged
  • If the input is Right and the predicate returns true, the Right value passes through unchanged
  • If the input is Right and the predicate returns false, it's converted to Left(empty)

This function is useful for conditional validation or filtering of Either values, where you want to reject Right values that don't meet certain criteria by converting them to Left values with a default error.

Parameters:

  • p: A predicate function that tests values of type A
  • empty: The default Left value to use when filtering out Right values that fail the predicate

Returns:

An Operator function that takes an Either[E, A] and returns an Either[E, A] where:
  - Left values pass through unchanged
  - Right values that pass the predicate remain as Right
  - Right values that fail the predicate become Left(empty)

Example:

import (
    E "github.com/IBM/fp-go/v2/either"
    N "github.com/IBM/fp-go/v2/number"
)

// EitherFilter to keep only positive numbers
isPositive := N.MoreThan(0)
filterPositive := E.EitherFilter(isPositive, "not positive")

// Right value that passes predicate - remains Right
result1 := filterPositive(E.Right[string](5))
// result1 = Right(5)

// Right value that fails predicate - becomes Left
result2 := filterPositive(E.Right[string](-3))
// result2 = Left("not positive")

// Left value passes through unchanged
result3 := filterPositive(E.EitherLeft[int]("original error"))
// result3 = Left("original error")

// Chaining filters
isEven := func(n int) bool { return n%2 == 0 }
filterEven := E.EitherFilter(isEven, "not even")

// Apply multiple filters in sequence
result4 := filterEven(filterPositive(E.Right[string](4)))
// result4 = Right(4) - passes both filters

result5 := filterEven(filterPositive(E.Right[string](3)))
// result5 = Left("not even") - passes first, fails second

func EitherFilterMap added in v2.3.122

func EitherFilterMap[E, A, B any](f OptionKleisli[A, B], empty E) EitherOperator[E, A, B]

EitherFilterMap combines filtering and mapping operations for Either values using an Option-returning function. It returns a function that takes an Either[E, A] and produces an Either[E, B], where Right values are transformed by applying the function f. If f returns Some(B), the result is Right(B). If f returns None, the result is Left(empty).

This function implements the Filterable specification's filterMap operation: https://github.com/fantasyland/fantasy-land#filterable

The behavior is as follows:

  • If the input is Left, it passes through with its error value preserved as EitherLeft[B]
  • If the input is Right and f returns Some(B), the result is Right(B)
  • If the input is Right and f returns None, the result is Left(empty)

This function is useful for operations that combine validation/filtering with transformation, such as parsing strings to numbers (where invalid strings result in None), or extracting optional fields from structures.

Parameters:

  • f: An Option Kleisli function that transforms values of type A to Option[B]
  • empty: The default Left value to use when f returns None

Returns:

An Operator function that takes an Either[E, A] and returns an Either[E, B] where:
  - Left values pass through with error preserved
  - Right values are transformed by f: Some(B) becomes Right(B), None becomes Left(empty)

Example:

import (
    E "github.com/IBM/fp-go/v2/either"
    O "github.com/IBM/fp-go/v2/option"
    "strconv"
)

// Parse string to int, filtering out invalid values
parseInt := func(s string) O.Option[int] {
    if n, err := strconv.Atoi(s); err == nil {
        return O.Some(n)
    }
    return O.None[int]()
}
filterMapInt := E.EitherFilterMap(parseInt, "invalid number")

// Valid number string - transforms to Right(int)
result1 := filterMapInt(E.Right[string]("42"))
// result1 = Right(42)

// Invalid number string - becomes Left
result2 := filterMapInt(E.Right[string]("abc"))
// result2 = Left("invalid number")

// Left value passes through with error preserved
result3 := filterMapInt(E.EitherLeft[string]("original error"))
// result3 = Left("original error")

// Extract optional field from struct
type Person struct {
    Name  string
    Email O.Option[string]
}
extractEmail := func(p Person) O.Option[string] { return p.Email }
filterMapEmail := E.EitherFilterMap(extractEmail, "no email")

result4 := filterMapEmail(E.Right[string](Person{Name: "Alice", Email: O.Some("alice@example.com")}))
// result4 = Right("alice@example.com")

result5 := filterMapEmail(E.Right[string](Person{Name: "Bob", Email: O.None[string]()}))
// result5 = Left("no email")

func EitherFlap added in v2.3.122

func EitherFlap[E, B, A any](a A) EitherOperator[E, func(A) B, B]

EitherFlap is the curried version of EitherMonadFlap.

func EitherMap added in v2.3.122

func EitherMap[E, A, B any](f func(A) B) EitherOperator[E, A, B]

EitherMap is the curried version of EitherMonadMap. Transforms the Right value using the provided function.

func EitherMapTo added in v2.3.122

func EitherMapTo[E, A, B any](b B) EitherOperator[E, A, B]

EitherMapTo is the curried version of EitherMonadMapTo.

type EitherTraversable added in v2.3.122

type EitherTraversable[E, A, B, GA, GB any] = func(EitherKleisli[E, A, B]) EitherKleisli[E, GA, GB]

func EitherTraversableArray added in v2.3.122

func EitherTraversableArray[E, A, B any]() EitherTraversable[E, A, B, []A, []B]

func EitherTraversableRecord added in v2.3.122

func EitherTraversableRecord[K comparable, E, A, B any]() EitherTraversable[E, A, B, map[K]A, map[K]B]

type Endomorphism

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

Endomorphism is a function from a type to itself (A → A). It represents transformations that preserve the type.

type Iso

type Iso[S, A any] struct {

	// Get converts a value from the source type S to the target type A.
	Get func(s S) A

	// ReverseGet converts a value from the target type A back to the source type S.
	// This is the inverse of Get.
	ReverseGet func(a A) S
	// contains filtered or unexported fields
}

Iso represents an isomorphism between types S and A. An isomorphism is a bidirectional transformation that converts between two types without any loss of information. It consists of two functions that are inverses of each other.

Type Parameters:

  • S: The source type
  • A: The target type

Fields:

  • Get: Converts from S to A
  • ReverseGet: Converts from A back to S

Laws: An Iso must satisfy the round-trip laws:

  1. ReverseGet(Get(s)) == s for all s: S
  2. Get(ReverseGet(a)) == a for all a: A

Example:

// Isomorphism between Celsius and Fahrenheit
tempIso := Iso[float64, float64]{
    Get: func(c float64) float64 { return c*9/5 + 32 },
    ReverseGet: func(f float64) float64 { return (f - 32) * 5 / 9 },
}

fahrenheit := tempIso.Get(20.0)        // 68.0
celsius := tempIso.ReverseGet(68.0)    // 20.0

func IsoId

func IsoId[S any]() Iso[S, S]

IsoId returns an identity isomorphism that performs no transformation. Both Get and ReverseGet are the identity function.

Type Parameters:

  • S: The type for both source and target

Returns:

  • An Iso[S, S] where Get and ReverseGet are both identity functions

Example:

idIso := IsoId[int]()
value := idIso.Get(42)        // 42
same := idIso.ReverseGet(42)  // 42

Use cases:

  • As a starting point for isomorphism composition
  • When you need an isomorphism but don't want to transform the value
  • In generic code that requires an isomorphism parameter

func IsoReverse

func IsoReverse[S, A any](sa Iso[S, A]) Iso[A, S]

IsoReverse swaps the direction of an isomorphism. Given Iso[S, A], creates Iso[A, S] where Get and ReverseGet are swapped.

Type Parameters:

  • S: The original source type (becomes target)
  • A: The original target type (becomes source)

Parameters:

  • sa: The isomorphism to reverse

Returns:

  • An Iso[A, S] with Get and ReverseGet swapped

Example:

celsiusToFahrenheit := MakeIso(
    func(c float64) float64 { return c*9/5 + 32 },
    func(f float64) float64 { return (f - 32) * 5 / 9 },
)

// IsoReverse to get Fahrenheit to Celsius
fahrenheitToCelsius := IsoReverse(celsiusToFahrenheit)

celsius := fahrenheitToCelsius.Get(68.0)        // 20.0
fahrenheit := fahrenheitToCelsius.ReverseGet(20.0) // 68.0

func MakeIso

func MakeIso[S, A any](get func(S) A, reverse func(A) S) Iso[S, A]

MakeIso constructs an isomorphism from two functions. The functions should be inverses of each other to satisfy the isomorphism laws.

Type Parameters:

  • S: The source type
  • A: The target type

Parameters:

  • get: Function to convert from S to A
  • reverse: Function to convert from A to S (inverse of get)

Returns:

  • An Iso[S, A] that uses the provided functions

Example:

// Create an isomorphism between string and []byte
stringBytesIso := MakeIso(
    func(s string) []byte { return []byte(s) },
    func(b []byte) string { return string(b) },
)

bytes := stringBytesIso.Get("hello")           // []byte("hello")
str := stringBytesIso.ReverseGet([]byte("hi")) // "hi"

func (Iso[S, A]) Compose

func (p Iso[S, A]) Compose[B any](ab Iso[A, B]) Iso[S, B]

Compose returns a new isomorphism that focuses deeper by chaining this isomorphism (S → A) with an inner isomorphism (A → B), producing a composed isomorphism (S → B).

This is the method-receiver form of the package-level OptionalComposeOptional function, available only on Go 1.27 and later because Go did not support type parameters on methods before that version. On earlier toolchains, use the equivalent free function instead:

// method form (go1.27+)
composed := outerIso.Compose(innerIso)

// free-function form (all versions)
composed := iso.Compose[S](innerIso)(outerIso)

Get of the composed isomorphism applies the outer Get followed by the inner Get: composed.Get(s) = ab.Get(sa.Get(s)).

ReverseGet of the composed isomorphism applies the inner ReverseGet followed by the outer ReverseGet: composed.ReverseGet(b) = sa.ReverseGet(ab.ReverseGet(b)).

The composed isomorphism satisfies both iso round-trip laws whenever both constituent isomorphisms individually satisfy them:

composed.ReverseGet(composed.Get(s)) == s    for all s: S
composed.Get(composed.ReverseGet(b)) == b    for all b: B

Type Parameters:

  • B: the target type of the inner isomorphism and of the resulting isomorphism

Parameters:

  • ab: the inner isomorphism from A to B

Returns:

  • Iso[S, B]: a new isomorphism from S directly to B

See Also:

  • Compose: the equivalent package-level function
  • Reverse: swaps the direction of an isomorphism

func (Iso[S, A]) ComposeLens

func (p Iso[S, A]) ComposeLens[B any](ab Lens[A, B]) Lens[S, B]

ComposeLens returns a new lens by composing this isomorphism (S ↔ A) with an inner lens (A → B), producing a Lens[S, B].

Internally the isomorphism is first converted to a Lens[S, A] via IsoAsLens, then composed with the provided lens using LensComposeLens. The result focuses on a value of type B that is reached by first applying the isomorphism's Get direction and then the inner lens's Get.

This is the method-receiver form of the package-level IsoComposeLens function, available only on Go 1.27 and later because Go did not support type parameters on methods before that version. On earlier toolchains use the equivalent free function:

// method form (go1.27+)
streetLens := addressIso.ComposeLens(streetFieldLens)

// free-function form (all versions)
streetLens := IsoComposeLens[S](streetFieldLens)(addressIso)

The resulting lens satisfies all three lens laws whenever both the isomorphism and the inner lens individually satisfy them.

Type Parameters:

  • B: the focus type of the inner lens and of the resulting lens

Parameters:

  • ab: the inner lens from A to B

Returns:

  • Lens[S, B]: a new lens from S directly to B

See Also:

  • Compose: the equivalent method for composing with an Iso[A, B] instead of a Lens[A, B]
  • IsoComposeLens: the equivalent package-level function

func (Iso) Format

func (Iso) Format(f fmt.State, c rune)

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

  • %s, %v, %+v, %q, and all other verbs: uses String() representation

The exact output format is not a stable contract and may change across versions.

func (Iso) LogValue

func (Iso) LogValue() slog.Value

func (Iso) String

func (Iso) String() string

String returns a string representation of the isomorphism. The exact format is not a stable contract and may change across versions.

Example:

tempIso := iso.MakeIso(...)
fmt.Println(tempIso)  // Prints: "Iso"

type Lens

type Lens[S, A any] struct {

	// Get extracts the focused value of type A from structure S.
	Get func(s S) A

	// Set returns a function that updates the focused value in structure S.
	// The returned function takes a structure S and returns a new structure S
	// with the focused value updated to a. The original structure is never modified.
	Set func(a A) Endomorphism[S]
	// contains filtered or unexported fields
}

Lens is a functional reference to a subpart of a data structure.

A Lens[S, A] provides a composable way to focus on a field of type A within a structure of type S. It consists of two operations:

  • Get: Extracts the focused value from the structure (S → A)
  • Set: Updates the focused value in the structure, returning a new structure (A → S → S)

Lenses maintain immutability by always returning new copies of the structure when setting values, never modifying the original.

Type Parameters:

  • S: The source/structure type (the whole)
  • A: The focus/field type (the part)

Lens Laws:

A well-behaved lens must satisfy three laws:

  1. GetSet (You get what you set): lens.Set(lens.Get(s))(s) == s
  1. SetGet (You set what you get): lens.Get(lens.Set(a)(s)) == a
  1. SetSet (Setting twice is the same as setting once): lens.Set(a2)(lens.Set(a1)(s)) == lens.Set(a2)(s)

Example Usage:

type Person struct {
    Name string
    Age  int
}

// Create a lens focusing on the Name field
nameLens := lens.MakeLens(
    func(p Person) string { return p.Name },
    func(name string) func(Person) Person {
        return func(p Person) Person {
            return Person{Name: name, Age: p.Age}
        }
    },
)

person := Person{Name: "Alice", Age: 30}
name := nameLens.Get(person)           // Returns: "Alice"
updated := nameLens.Set("Bob")(person) // Returns: Person{Name: "Bob", Age: 30}
// Original person remains unchanged (immutability preserved)

func IsoAsLens

func IsoAsLens[S, A any](sa Iso[S, A]) Lens[S, A]

IsoAsLens converts an Iso[S, A] into a Lens[S, A].

The resulting lens uses the iso's Get as its getter and its ReverseGet as its setter. Because an isomorphism is total and invertible, Set always replaces the focused value by applying ReverseGet — the original S is discarded.

Type Parameters:

  • S: The source type of the isomorphism and of the resulting lens
  • A: The target type of the isomorphism and the focus type of the resulting lens

Parameters:

  • sa: The isomorphism to convert

Returns:

  • Lens[S, A]: a lens whose Get is sa.Get and whose Set is sa.ReverseGet

See Also:

  • IsoAsLensRef: the pointer-receiver variant for Iso[*S, A]

func IsoAsLensRef deprecated

func IsoAsLensRef[S, A any](sa Iso[*S, A]) Lens[*S, A]

IsoAsLensRef converts an Iso[*S, A] into a Lens[*S, A] for pointer-based structures.

This is the pointer-receiver variant of IsoAsLens. It accepts an isomorphism whose source type is already a pointer (*S) and wraps the resulting lens with copy-on-write semantics: before the setter is applied, a shallow copy of *S is made so that the original value is never mutated. A nil pointer is handled safely by substituting a zero-value S.

In practice the copy-on-write wrapper is a no-op for an iso-derived setter, because the setter is simply ReverseGet(a) and ignores the incoming *S entirely. The wrapper exists for consistency with other pointer lenses and to guard against nil inputs.

Deprecated: IsoAsLens[*S, A] is sufficient because the copy-on-write wrapper added by this function has no observable effect for iso-derived setters. Prefer IsoAsLens unless you specifically need the nil-pointer safety on the incoming *S, which the iso's ReverseGet already cannot depend on.

Type Parameters:

  • S: The pointee type; the isomorphism source is *S
  • A: The target type of the isomorphism and the focus type of the resulting lens

Parameters:

  • sa: The isomorphism from *S to A to convert

Returns:

  • Lens[*S, A]: a lens whose Get is sa.Get and whose Set applies sa.ReverseGet with copy-on-write protection on the *S receiver

See Also:

  • IsoAsLens: the general form that accepts any Iso[S, A], including Iso[*S, A]

func LensId

func LensId[S any]() Lens[S, S]

LensId returns an identity Lens that focuses on the entire structure.

The identity lens is useful as a starting point for lens composition or when you need a lens that doesn't actually focus on a subpart. Get returns the structure unchanged, and Set replaces the entire structure.

Type Parameters:

  • S: The structure type

Returns:

  • A Lens[S, S] where both source and focus are the same type

Example:

type Person struct {
    Name string
    Age  int
}

idLens := lens.LensId[Person]()
person := Person{Name: "Alice", Age: 30}

same := idLens.Get(person)  // Returns person unchanged
replaced := idLens.Set(Person{Name: "Bob", Age: 25})(person)
// replaced is Person{Name: "Bob", Age: 25}

func LensIdRef

func LensIdRef[S any]() Lens[*S, *S]

LensIdRef returns an identity Lens for pointer-based structures.

This is the pointer version of LensId. It focuses on the entire pointer structure, with automatic copying to ensure immutability.

Type Parameters:

  • S: The structure type (will be used as *S)

Returns:

  • A Lens[*S, *S] where both source and focus are pointers to the same type

Example:

idLens := lens.LensIdRef[Person]()
person := &Person{Name: "Alice", Age: 30}

same := idLens.Get(person)  // Returns person pointer
replaced := idLens.Set(&Person{Name: "Bob", Age: 25})(person)
// person.Name is still "Alice", replaced is a new pointer

func MakeLens

func MakeLens[GET ~func(S) A, SET ~func(S, A) S, S, A any](get GET, set SET) Lens[S, A]

MakeLens creates a Lens based on a getter and a setter F.

The setter must create a (shallow) copy of the data structure. This happens automatically when the data is passed by value. For pointer-based structures, use MakeLensRef instead. For other reference types (slices, maps), ensure the setter creates a copy.

Type Parameters:

  • GET: Getter function type (S → A)
  • SET: Setter function type (S, A → S)
  • S: Source structure type
  • A: Focus/field type

Parameters:

  • get: Function to extract value A from structure S
  • set: Function to update value A in structure S, returning a new S

Returns:

  • A Lens[S, A] that can get and set values immutably

Example:

type Person struct {
    Name string
    Age  int
}

nameLens := lens.MakeLens(
    func(p Person) string { return p.Name },
    func(p Person, name string) Person {
        p.Name = name
        return p
    },
)

person := Person{Name: "Alice", Age: 30}
name := nameLens.Get(person)           // "Alice"
updated := nameLens.Set("Bob")(person) // Person{Name: "Bob", Age: 30}

func MakeLensCurried

func MakeLensCurried[GET ~func(S) A, SET ~func(A) Endomorphism[S], S, A any](get GET, set SET) Lens[S, A]

MakeLensCurried creates a Lens with a curried setter F.

This is similar to MakeLens but accepts a curried setter (A → S → S) instead of an uncurried one (S, A → S). The curried form is more composable in functional pipelines.

The setter must create a (shallow) copy of the data structure. This happens automatically when the data is passed by value. For pointer-based structures, use MakeLensRefCurried.

Type Parameters:

  • GET: Getter function type (S → A)
  • SET: Curried setter function type (A → S → S)
  • S: Source structure type
  • A: Focus/field type

Parameters:

  • get: Function to extract value A from structure S
  • set: Curried function to update value A in structure S

Returns:

  • A Lens[S, A] that can get and set values immutably

Example:

nameLens := lens.MakeLensCurried(
    func(p Person) string { return p.Name },
    func(name string) func(Person) Person {
        return func(p Person) Person {
            p.Name = name
            return p
        }
    },
)

func MakeLensCurriedRefWithName

func MakeLensCurriedRefWithName[GET ~func(*S) A, SET ~func(A) Endomorphism[*S], S, A any](get GET, set SET, name string) Lens[*S, A]

MakeLensCurriedRefWithName creates a Lens for pointer-based structures with a curried setter and a custom name.

This is the named variant of MakeLensCurriedRefWithName combined with automatic copy-on-write semantics for pointer receivers. The setter does not need to create a copy manually; the copy is applied by the wrapped curried setter produced by setCopyCurried. The name is used in String, Format, and LogValue for debugging and structured logging.

Type Parameters:

  • GET: Getter function type (*S → A)
  • SET: Curried setter function type (A → *S → *S)
  • S: Source structure type (will be used as *S)
  • A: Focus/field type

Parameters:

  • get: Function to extract value A from pointer *S
  • set: Curried function to update value A in pointer *S (copying handled automatically)
  • name: A descriptive name for the lens (used in String() and Format())

Returns:

  • A Lens[*S, A] with the specified name

func MakeLensCurriedWithName

func MakeLensCurriedWithName[GET ~func(S) A, SET ~func(A) Endomorphism[S], S, A any](get GET, set SET, name string) Lens[S, A]

MakeLensCurriedWithName creates a Lens with a curried setter and a custom name.

This combines the benefits of MakeLensCurried (curried setter for better composition) with MakeLensWithName (custom name for debugging). The name is useful for debugging complex lens compositions and understanding which lens is being used in error messages or logs.

The setter must create a (shallow) copy of the data structure. This happens automatically when the data is passed by value. For pointer-based structures, use MakeLensRefCurried.

Type Parameters:

  • GET: Getter function type (S → A)
  • SET: Curried setter function type (A → S → S)
  • S: Source structure type
  • A: Focus/field type

Parameters:

  • get: Function to extract value A from structure S
  • set: Curried function to update value A in structure S
  • name: A descriptive name for the lens (used in String() and Format())

Returns:

  • A Lens[S, A] with the specified name

Example:

type Person struct {
    Name string
    Age  int
}

nameLens := lens.MakeLensCurriedWithName(
    func(p Person) string { return p.Name },
    func(name string) func(Person) Person {
        return func(p Person) Person {
            p.Name = name
            return p
        }
    },
    "Person.Name",
)

fmt.Printf("Using lens: %s\n", nameLens)  // Prints: "Using lens: Person.Name"

func MakeLensRef

func MakeLensRef[GET ~func(*S) A, SET func(*S, A) *S, S, A any](get GET, set SET) Lens[*S, A]

MakeLensRef creates a Lens for pointer-based structures.

Unlike MakeLens, the setter does not need to create a copy manually. This function automatically wraps the setter to create a shallow copy of the pointed-to value before modification, ensuring immutability.

This lens assumes that property A always exists in structure S (i.e., it's not optional).

Type Parameters:

  • GET: Getter function type (*S → A)
  • SET: Setter function type (*S, A → *S)
  • S: Source structure type (will be used as *S)
  • A: Focus/field type

Parameters:

  • get: Function to extract value A from pointer *S
  • set: Function to update value A in pointer *S (copying handled automatically)

Returns:

  • A Lens[*S, A] that can get and set values immutably on pointers

Example:

type Person struct {
    Name string
    Age  int
}

nameLens := lens.MakeLensRef(
    func(p *Person) string { return p.Name },
    func(p *Person, name string) *Person {
        p.Name = name  // No manual copy needed
        return p
    },
)

person := &Person{Name: "Alice", Age: 30}
updated := nameLens.Set("Bob")(person)
// person.Name is still "Alice", updated is a new pointer with Name "Bob"

func MakeLensRefCurried

func MakeLensRefCurried[S, A any](get func(*S) A, set func(A) Endomorphism[*S]) Lens[*S, A]

MakeLensRefCurried creates a Lens for pointer-based structures with a curried setter.

This combines the benefits of MakeLensRef (automatic copying) with MakeLensCurried (curried setter for better composition). The setter does not need to create a copy manually; this function automatically wraps it to ensure immutability.

This lens assumes that property A always exists in structure S (i.e., it's not optional).

Type Parameters:

  • S: Source structure type (will be used as *S)
  • A: Focus/field type

Parameters:

  • get: Function to extract value A from pointer *S
  • set: Curried function to update value A in pointer *S (copying handled automatically)

Returns:

  • A Lens[*S, A] that can get and set values immutably on pointers

Example:

nameLens := lens.MakeLensRefCurried(
    func(p *Person) string { return p.Name },
    func(name string) func(*Person) *Person {
        return func(p *Person) *Person {
            p.Name = name  // No manual copy needed
            return p
        }
    },
)

func MakeLensRefCurriedWithName

func MakeLensRefCurriedWithName[S, A any](get func(*S) A, set func(A) Endomorphism[*S], name string) Lens[*S, A]

MakeLensRefCurriedWithName creates a Lens for pointer-based structures with a curried setter and custom name.

This combines the benefits of MakeLensRefCurried (automatic copying with curried setter) with MakeLensWithName (custom name for debugging). The setter does not need to create a copy manually; this function automatically wraps it to ensure immutability. The curried form is more composable in functional pipelines, and the name is useful for debugging.

This lens assumes that property A always exists in structure S (i.e., it's not optional).

Type Parameters:

  • S: Source structure type (will be used as *S)
  • A: Focus/field type

Parameters:

  • get: Function to extract value A from pointer *S
  • set: Curried function to update value A in pointer *S (copying handled automatically)
  • name: A descriptive name for the lens (used in String() and Format())

Returns:

  • A Lens[*S, A] with the specified name

Example:

type Person struct {
    Name string
    Age  int
}

nameLens := lens.MakeLensRefCurriedWithName(
    func(p *Person) string { return p.Name },
    func(name string) func(*Person) *Person {
        return func(p *Person) *Person {
            p.Name = name  // No manual copy needed
            return p
        }
    },
    "Person.Name",
)

person := &Person{Name: "Alice", Age: 30}
fmt.Printf("Using lens: %s\n", nameLens)  // Prints: "Using lens: Person.Name"
updated := nameLens.Set("Bob")(person)
// person.Name is still "Alice", updated is a new pointer with Name "Bob"

func MakeLensRefWithName

func MakeLensRefWithName[GET ~func(*S) A, SET func(*S, A) *S, S, A any](get GET, set SET, name string) Lens[*S, A]

MakeLensRefWithName creates a Lens for pointer-based structures with a custom name.

This combines MakeLensRef (automatic copying for pointer structures) with MakeLensWithName (custom name for debugging). The setter does not need to create a copy manually; this function automatically wraps it to ensure immutability. The name is useful for debugging complex lens compositions and understanding which lens is being used in error messages or logs.

This lens assumes that property A always exists in structure S (i.e., it's not optional).

Type Parameters:

  • GET: Getter function type (*S → A)
  • SET: Setter function type (*S, A → *S)
  • S: Source structure type (will be used as *S)
  • A: Focus/field type

Parameters:

  • get: Function to extract value A from pointer *S
  • set: Function to update value A in pointer *S (copying handled automatically)
  • name: A descriptive name for the lens (used in String() and Format())

Returns:

  • A Lens[*S, A] with the specified name

Example:

type Person struct {
    Name string
    Age  int
}

nameLens := lens.MakeLensRefWithName(
    func(p *Person) string { return p.Name },
    func(p *Person, name string) *Person {
        p.Name = name  // No manual copy needed
        return p
    },
    "Person.Name",
)

person := &Person{Name: "Alice", Age: 30}
fmt.Printf("Using lens: %s\n", nameLens)  // Prints: "Using lens: Person.Name"
updated := nameLens.Set("Bob")(person)
// person.Name is still "Alice", updated is a new pointer with Name "Bob"

func MakeLensStrict

func MakeLensStrict[GET ~func(*S) A, SET func(*S, A) *S, S any, A comparable](get GET, set SET) Lens[*S, A]

MakeLensStrict creates a Lens for pointer-based structures with strict equality optimization.

This is a convenience function that combines MakeLensWithEq with strict equality comparison (==). It's suitable for comparable types (primitives, strings, pointers, etc.) and provides the same optimization as MakeLensWithEq: if the new value equals the current value, the original pointer is returned unchanged instead of creating a copy.

The setter does not need to create a copy manually; this function automatically wraps it to ensure immutability when changes are made.

This lens assumes that property A always exists in structure S (i.e., it's not optional).

Type Parameters:

  • GET: Getter function type (*S → A)
  • SET: Setter function type (*S, A → *S)
  • S: Source structure type (will be used as *S)
  • A: Focus/field type (must be comparable)

Parameters:

  • get: Function to extract value A from pointer *S
  • set: Function to update value A in pointer *S (copying handled automatically)

Returns:

  • A Lens[*S, A] that can get and set values immutably on pointers with strict equality optimization

Example:

type Person struct {
    Name string
    Age  int
}

// Using MakeLensStrict for a string field (comparable type)
nameLens := lens.MakeLensStrict(
    func(p *Person) string { return p.Name },
    func(p *Person, name string) *Person {
        p.Name = name  // No manual copy needed
        return p
    },
)

person := &Person{Name: "Alice", Age: 30}

// Setting the same value returns the original pointer (no copy)
same := nameLens.Set("Alice")(person)
// same == person (same pointer)

// Setting a different value creates a new copy
updated := nameLens.Set("Bob")(person)
// person.Name is still "Alice", updated is a new pointer with Name "Bob"

func MakeLensStrictWithName

func MakeLensStrictWithName[GET ~func(*S) A, SET func(*S, A) *S, S any, A comparable](get GET, set SET, name string) Lens[*S, A]

MakeLensStrictWithName creates a Lens for pointer-based structures with strict equality optimization and a custom name.

This combines MakeLensStrict (strict equality optimization using ==) with MakeLensWithName (custom name for debugging). It's a convenience function suitable for comparable types (primitives, strings, pointers, etc.). If the new value equals the current value, the original pointer is returned unchanged instead of creating a copy. The name is useful for debugging.

The setter does not need to create a copy manually; this function automatically wraps it to ensure immutability when changes are made.

This lens assumes that property A always exists in structure S (i.e., it's not optional).

Type Parameters:

  • GET: Getter function type (*S → A)
  • SET: Setter function type (*S, A → *S)
  • S: Source structure type (will be used as *S)
  • A: Focus/field type (must be comparable)

Parameters:

  • get: Function to extract value A from pointer *S
  • set: Function to update value A in pointer *S (copying handled automatically)
  • name: A descriptive name for the lens (used in String() and Format())

Returns:

  • A Lens[*S, A] with strict equality optimization and the specified name

Example:

type Person struct {
    Name string
    Age  int
}

// Using MakeLensStrictWithName for a string field (comparable type)
nameLens := lens.MakeLensStrictWithName(
    func(p *Person) string { return p.Name },
    func(p *Person, name string) *Person {
        p.Name = name  // No manual copy needed
        return p
    },
    "Person.Name",
)

person := &Person{Name: "Alice", Age: 30}
fmt.Printf("Using lens: %s\n", nameLens)  // Prints: "Using lens: Person.Name"

// Setting the same value returns the original pointer (no copy)
same := nameLens.Set("Alice")(person)  // same == person

// Setting a different value creates a new copy
updated := nameLens.Set("Bob")(person)  // person.Name still "Alice"

func MakeLensWithEq

func MakeLensWithEq[GET ~func(*S) A, SET func(*S, A) *S, S, A any](pred EQ.Eq[A], get GET, set SET) Lens[*S, A]

MakeLensWithEq creates a Lens for pointer-based structures with equality optimization.

This is similar to MakeLensRef but includes an optimization: if the new value equals the current value (according to the provided Eq predicate), the original pointer is returned unchanged instead of creating a copy. This can improve performance and reduce allocations when setting values that don't actually change the structure.

The setter does not need to create a copy manually; this function automatically wraps it to ensure immutability when changes are made.

This lens assumes that property A always exists in structure S (i.e., it's not optional).

Type Parameters:

  • GET: Getter function type (*S → A)
  • SET: Setter function type (*S, A → *S)
  • S: Source structure type (will be used as *S)
  • A: Focus/field type

Parameters:

  • pred: Equality predicate to compare values of type A
  • get: Function to extract value A from pointer *S
  • set: Function to update value A in pointer *S (copying handled automatically)

Returns:

  • A Lens[*S, A] that can get and set values immutably on pointers with equality optimization

Example:

type Person struct {
    Name string
    Age  int
}

nameLens := lens.MakeLensWithEq(
    eq.FromStrictEquals[string](),
    func(p *Person) string { return p.Name },
    func(p *Person, name string) *Person {
        p.Name = name  // No manual copy needed
        return p
    },
)

person := &Person{Name: "Alice", Age: 30}

// Setting the same value returns the original pointer (no copy)
same := nameLens.Set("Alice")(person)
// same == person (same pointer)

// Setting a different value creates a new copy
updated := nameLens.Set("Bob")(person)
// person.Name is still "Alice", updated is a new pointer with Name "Bob"

func MakeLensWithEqWithName

func MakeLensWithEqWithName[GET ~func(*S) A, SET func(*S, A) *S, S, A any](pred EQ.Eq[A], get GET, set SET, name string) Lens[*S, A]

MakeLensWithEqWithName creates a Lens for pointer-based structures with equality optimization and a custom name.

This combines MakeLensWithEq (equality optimization) with MakeLensWithName (custom name for debugging). If the new value equals the current value (according to the provided Eq predicate), the original pointer is returned unchanged instead of creating a copy. The name is useful for debugging complex lens compositions.

The setter does not need to create a copy manually; this function automatically wraps it to ensure immutability when changes are made.

This lens assumes that property A always exists in structure S (i.e., it's not optional).

Type Parameters:

  • GET: Getter function type (*S → A)
  • SET: Setter function type (*S, A → *S)
  • S: Source structure type (will be used as *S)
  • A: Focus/field type

Parameters:

  • pred: Equality predicate to compare values of type A
  • get: Function to extract value A from pointer *S
  • set: Function to update value A in pointer *S (copying handled automatically)
  • name: A descriptive name for the lens (used in String() and Format())

Returns:

  • A Lens[*S, A] with equality optimization and the specified name

Example:

type Person struct {
    Name string
    Age  int
}

nameLens := lens.MakeLensWithEqWithName(
    eq.FromStrictEquals[string](),
    func(p *Person) string { return p.Name },
    func(p *Person, name string) *Person {
        p.Name = name  // No manual copy needed
        return p
    },
    "Person.Name",
)

person := &Person{Name: "Alice", Age: 30}
fmt.Printf("Using lens: %s\n", nameLens)  // Prints: "Using lens: Person.Name"

// Setting the same value returns the original pointer (no copy)
same := nameLens.Set("Alice")(person)  // same == person

// Setting a different value creates a new copy
updated := nameLens.Set("Bob")(person)  // person.Name still "Alice"

func MakeLensWithName

func MakeLensWithName[GET ~func(S) A, SET ~func(S, A) S, S, A any](get GET, set SET, name string) Lens[S, A]

MakeLensWithName creates a Lens with a custom name for debugging and logging.

This is identical to MakeLens but allows you to specify a name that will be used when the lens is printed or formatted. The name is useful for debugging complex lens compositions and understanding which lens is being used in error messages or logs.

The setter must create a (shallow) copy of the data structure. This happens automatically when the data is passed by value. For pointer-based structures, use MakeLensRef instead.

Type Parameters:

  • GET: Getter function type (S → A)
  • SET: Setter function type (S, A → S)
  • S: Source structure type
  • A: Focus/field type

Parameters:

  • get: Function to extract value A from structure S
  • set: Function to update value A in structure S, returning a new S
  • name: A descriptive name for the lens (used in String() and Format())

Returns:

  • A Lens[S, A] with the specified name

Example:

type Person struct {
    Name string
    Age  int
}

nameLens := lens.MakeLensWithName(
    func(p Person) string { return p.Name },
    func(p Person, name string) Person {
        p.Name = name
        return p
    },
    "Person.Name",
)

fmt.Printf("Using lens: %s\n", nameLens)  // Prints: "Using lens: Person.Name"

func (Lens[S, A]) Compose

func (l Lens[S, A]) Compose[B any](ab Lens[A, B]) Lens[S, B]

Compose returns a new lens that focuses deeper into the structure by chaining this lens (S → A) with an inner lens (A → B), producing a composed lens (S → B).

This is the method-receiver form of the package-level IsoComposeIso function, available only on Go 1.27 and later because Go did not support type parameters on methods before that version. On earlier toolchains, use the equivalent free function instead:

// method form (go1.27+)
personStreetLens := addressLens.Compose(streetLens)

// free-function form (all versions)
personStreetLens := lens.Compose[Person](streetLens)(addressLens)

The composed lens satisfies all three lens laws whenever both constituent lenses individually satisfy them.

Type Parameters:

  • B: the focus type of the inner lens and of the resulting lens

Parameters:

  • ab: the inner lens from A to B

Returns:

  • Lens[S, B]: a new lens from S directly to B

See Also:

  • Compose: the equivalent package-level function

func (Lens[S, A]) ComposeIso

func (l Lens[S, A]) ComposeIso[B any](ab Iso[A, B]) Lens[S, B]

ComposeIso returns a new lens that focuses on a value of type B by composing this lens (S → A) with an isomorphism (A ↔ B), producing a lens (S → B).

This is the method-receiver form of the package-level LensComposeIso function, available only on Go 1.27 and later because Go did not support type parameters on methods before that version. On earlier toolchains use the equivalent free function:

// method form (go1.27+)
fahrenheitLens := readingLens.ComposeIso(celsiusToFahrenheit)

// free-function form (all versions)
fahrenheitLens := LensComposeIso[Thermometer](celsiusToFahrenheit)(readingLens)

The resulting lens satisfies all three lens laws whenever both the outer lens and the isomorphism individually satisfy them.

Type Parameters:

  • B: the focus type of the resulting lens — the target type of the isomorphism

Parameters:

  • ab: the isomorphism from A to B

Returns:

  • Lens[S, B]: a new lens from S directly to B

See Also:

  • Compose: the equivalent method for composing with a Lens[A, B] instead of an Iso[A, B]
  • LensComposeIso: the equivalent package-level function

func (Lens[S, A]) ComposePrism added in v2.3.122

func (l Lens[S, A]) ComposePrism[B any](ab Prism[A, B]) Optional[S, B]

ComposePrism returns a new Optional that focuses on a value of type B by composing this lens (S → A) with a prism (A → B), producing an Optional (S → B).

This is the method-receiver form of the package-level LensComposePrism function, available only on Go 1.27 and later because Go did not support type parameters on methods before that version. On earlier toolchains use the equivalent free function:

// method form (go1.27+)
opt := myLens.ComposePrism(myPrism)

// free-function form (all versions)
opt := LensComposePrism[S](myPrism)(myLens)

The result is an Optional because the prism may not match the focused value. GetOption applies the lens first, then the prism; Set updates the structure only when GetOption would return Some — matching the Optional no-op law.

The composed Optional satisfies the standard Optional laws (GetSet, SetGet, SetSet) whenever the constituent lens and prism individually satisfy the lens and prism laws respectively.

Type Parameters:

  • B: the focus type of the prism and of the resulting Optional

Parameters:

  • ab: the prism from A to B

Returns:

  • Optional[S, B]: a new Optional from S directly to B

See Also:

  • Compose: method for composing with a Lens[A, B] instead of a Prism[A, B]
  • ComposeIso: method for composing with an Iso[A, B] instead of a Prism[A, B]
  • LensComposePrism: the equivalent package-level function

func (Lens) Format

func (l Lens) Format(f fmt.State, c rune)

Format implements fmt.Formatter.

Supports all standard format verbs:

  • %s, %v, %+v, %q, and all other verbs: uses the String() representation (the lens name)

The exact output format is not a stable contract and may change across versions.

func (Lens) LogValue

func (l Lens) LogValue() slog.Value

LogValue implements slog.LogValuer.

Returns a slog.Value that represents the lens for structured logging. The lens name is logged as a string value. The exact structure of the returned slog.Value is not a stable contract and may change across versions.

func (Lens[S, A]) Modify

func (la Lens[S, A]) Modify(f Endomorphism[A]) Endomorphism[S]

Modify applies a transformation function to the value focused by the lens.

This method transforms the focused value within a structure by applying an endomorphism (a function from A to A) and returns a new structure with the transformed value. The transformation is applied by first getting the current value, applying the function, and then setting the result back into the structure.

Type Parameters:

  • S: The structure type containing the focused value
  • A: The type of the focused value

Parameters:

  • f: An endomorphism that transforms the focused value

Returns:

  • An endomorphism on S that applies the transformation

Example:

type Person struct {
    Name string
    Age  int
}

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

person := Person{Name: "Alice", Age: 30}
incrementAge := ageLens.Modify(func(age int) int { return age + 1 })
older := incrementAge(person)
// older.Age == 31, person.Age == 30 (original unchanged)

See Also:

  • Modify: Package-level function for use in pipelines
  • Set: For setting a constant value instead of transforming

func (Lens) String

func (l Lens) String() string

String returns the name of the lens for debugging and display purposes. The exact format is not a stable contract and may change across versions.

type LensKleisli

type LensKleisli[S, A, B any] = func(A) Lens[S, B]

LensKleisli represents a function that takes a value of type A and returns a Lens[S, B]. This is useful for composing lenses in a monadic style, allowing for dynamic lens creation based on input values.

Type Parameters:

  • S: The source/structure type
  • A: The input type
  • B: The focus type of the resulting lens

type LensOperator

type LensOperator[S, A, B any] = LensKleisli[S, Lens[S, A], B]

LensOperator is a specialized Kleisli that takes a Lens[S, A] and returns a Lens[S, B]. This enables lens transformations and compositions where one lens is used to derive another.

Type Parameters:

  • S: The source/structure type
  • A: The focus type of the input lens
  • B: The focus type of the resulting lens

func LensComposeIso

func LensComposeIso[S, A, B any](ab Iso[A, B]) LensOperator[S, A, B]

LensComposeIso converts a Lens to a property of `A` into a lens to a property of type `B` the transformation is done via an ISO

func LensComposeLens

func LensComposeLens[S, A, B any](ab Lens[A, B]) LensOperator[S, A, B]

LensComposeLens combines two lenses to focus on a deeply nested field.

Given a lens from S to A and a lens from A to B, LensComposeLens creates a lens from S to B. This allows you to navigate through nested structures in a composable way.

The composition follows the mathematical property: (sa ∘ ab).Get = ab.Get ∘ sa.Get

Type Parameters:

  • S: Outer structure type
  • A: Intermediate structure type
  • B: Inner focus type

Parameters:

  • ab: Lens from A to B (inner lens)

Returns:

  • A function that takes a Lens[S, A] and returns a Lens[S, B]

Example:

type Address struct {
    Street string
    City   string
}

type Person struct {
    Name    string
    Address Address
}

addressLens := lens.MakeLens(
    func(p Person) Address { return p.Address },
    func(p Person, a Address) Person { p.Address = a; return p },
)

streetLens := lens.MakeLens(
    func(a Address) string { return a.Street },
    func(a Address, s string) Address { a.Street = s; return a },
)

// LensComposeLens to access street directly from person
personStreetLens := F.Pipe1(addressLens, lens.LensComposeLens[Person](streetLens))

person := Person{Name: "Alice", Address: Address{Street: "Main St"}}
street := personStreetLens.Get(person)  // "Main St"
updated := personStreetLens.Set("Oak Ave")(person)

func LensComposeLensRef deprecated

func LensComposeLensRef[S, A, B any](ab Lens[A, B]) LensOperator[*S, A, B]

LensComposeLensRef combines two lenses for pointer-based structures.

Deprecated: LensComposeLensRef is not needed. When the outer lens is already a pointer lens (Lens[*S, A], created with MakeLensRef or MakeLensRefCurried), its Set implementation already copies *S before writing. The copy that LensComposeLensRef adds via MakeLensRefCurriedWithName is therefore redundant — the composed setter calls the outer lens's Set, which copies, so the original pointer is never mutated.

Use LensComposeLens[*S] instead:

// Before
personStreetLens := F.Pipe1(addressLens, lens.LensComposeLensRef[Person](streetLens))

// After — identical behaviour, no extra copy
personStreetLens := F.Pipe1(addressLens, lens.Compose[*Person](streetLens))

Type Parameters:

  • S: Outer structure type (will be used as *S)
  • A: Intermediate structure type
  • B: Inner focus type

Parameters:

  • ab: Lens from A to B (inner lens)

Returns:

  • A function that takes a Lens[*S, A] and returns a Lens[*S, B]

func LensIMap

func LensIMap[S any, AB ~func(A) B, BA ~func(B) A, A, B any](ab AB, ba BA) LensOperator[S, A, B]

LensIMap transforms the focus type of a lens using an isomorphism.

An isomorphism is a pair of functions (A → B, B → A) that are inverses of each other. LensIMap allows you to work with a lens in a different but equivalent type. This is useful for unit conversions, encoding/decoding, or any bidirectional transformation.

Type Parameters:

  • E: Structure type
  • AB: Forward transformation function type (A → B)
  • BA: Backward transformation function type (B → A)
  • A: Original focus type
  • B: Transformed focus type

Parameters:

  • ab: Forward transformation (A → B)
  • ba: Backward transformation (B → A)

Returns:

  • A function that takes a Lens[E, A] and returns a Lens[E, B]

Example:

type Celsius float64
type Fahrenheit float64

celsiusToFahrenheit := func(c Celsius) Fahrenheit {
    return Fahrenheit(c*9/5 + 32)
}

fahrenheitToCelsius := func(f Fahrenheit) Celsius {
    return Celsius((f - 32) * 5 / 9)
}

type Weather struct {
    Temperature Celsius
}

tempCelsiusLens := lens.MakeLens(
    func(w Weather) Celsius { return w.Temperature },
    func(w Weather, t Celsius) Weather { w.Temperature = t; return w },
)

// Create a lens that works with Fahrenheit
tempFahrenheitLens := F.Pipe1(
    tempCelsiusLens,
    lens.LensIMap[Weather](celsiusToFahrenheit, fahrenheitToCelsius),
)

weather := Weather{Temperature: 20} // 20°C
tempF := tempFahrenheitLens.Get(weather)  // 68°F
updated := tempFahrenheitLens.Set(86)(weather)  // Set to 86°F (30°C)

type Option

type Option[A any] struct {
	// contains filtered or unexported fields
}

Option defines a data structure that logically holds a value or not. It represents an optional value: every Option is either Some and contains a value, or None, and does not contain a value.

Option is commonly used to represent the result of operations that may fail, as an alternative to returning nil pointers or using error values.

Example:

var opt Option[int] = Some(42)  // Contains a value
var opt Option[int] = None[int]() // Contains no value

func EitherToOption added in v2.3.122

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

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

Example:

result := either.EitherToOption(either.EitherRight[error](42)) // Some(42)
result := either.EitherToOption(either.EitherLeft[int](errors.New("err"))) // None

func OptionFlatten added in v2.3.120

func OptionFlatten[A any](mma Option[Option[A]]) Option[A]

OptionFlatten removes one level of nesting from a nested Option.

Example:

nested := OptionSome(OptionSome(42))
result := OptionFlatten(nested) // OptionSome(42)
nested := OptionSome(OptionNone[int]())
result := OptionFlatten(nested) // None

func OptionFromNillable deprecated added in v2.3.120

func OptionFromNillable[A any](a *A) Option[*A]

OptionFromNillable converts a pointer to an Option wrapping the pointer itself. Returns OptionSome(*A) when the pointer is non-nil, None otherwise.

Deprecated: Use FromNillable2 instead. FromNillable2 unwraps the pointed-to value into an Option[A], which is the more useful form: it avoids carrying a *A inside the Option and composes naturally with the rest of the Option API.

func OptionFromNillable2 added in v2.3.120

func OptionFromNillable2[A any](a *A) Option[A]

OptionFromNillable2 converts a pointer to an Option of the pointed-to value. Returns OptionSome(value) when the pointer is non-nil (dereferencing it), None otherwise. This is the preferred alternative to FromNillable because the resulting Option[A] composes naturally with Map, Chain, and the rest of the Option API without having to deal with an intermediate pointer inside the Option.

Type Parameters:

  • A: the type that the pointer points to

Parameters:

  • a: a pointer to a value of type A; may be nil

Returns:

  • OptionSome(*a) when a is non-nil
  • None when a is nil

See Also:

  • ToNillable2: the inverse — converts Option[A] back to *A
  • FromNillable: the older variant that wraps the pointer itself as Option[*A]

func OptionInstanceOf added in v2.3.120

func OptionInstanceOf[T any](src any) Option[T]

OptionInstanceOf attempts to convert a value of type any to a specific type T using type assertion. Returns Some(value) if the type assertion succeeds, None if it fails.

Example:

var x any = 42
result := OptionInstanceOf[int](x) // Some(42)

var y any = "hello"
result := OptionInstanceOf[int](y) // None (wrong type)

func OptionMonadAlt added in v2.3.120

func OptionMonadAlt[A any](fa Option[A], that func() Option[A]) Option[A]

MonadAlt returns the first Option if it's Some, otherwise returns the alternative. This is the monadic form of the Alt operation.

Example:

result := MonadAlt(OptionSome(5), func() Option[int] { return OptionSome(10) }) // OptionSome(5)
result := MonadAlt(OptionNone[int](), func() Option[int] { return OptionSome(10) }) // OptionSome(10)

func OptionMonadAp added in v2.3.120

func OptionMonadAp[B, A any](fab Option[func(A) B], fa Option[A]) Option[B]

OptionMonadAp applies a function wrapped in an Option to a value wrapped in an Option. If either the function or the value is None, returns None. This is the monadic form of the applicative functor.

Example:

fab := OptionSome(N.Mul(2))
fa := OptionSome(5)
result := OptionMonadAp(fab, fa) // OptionSome(10)

func OptionMonadChain added in v2.3.120

func OptionMonadChain[A, B any](fa Option[A], f OptionKleisli[A, B]) Option[B]

OptionMonadChain applies a function that returns an Option to the value inside an Option. This is the monadic bind operation. If the input is None, returns None.

Example:

fa := OptionSome(5)
result := OptionMonadChain(fa, F.Flow2(Predicate(N.MoreThan(0)), Map(N.Mul(2)))) // OptionSome(10)

func OptionMonadChainFirst added in v2.3.120

func OptionMonadChainFirst[A, B any](ma Option[A], f OptionKleisli[A, B]) Option[A]

OptionMonadChainFirst applies a function that returns an Option but keeps the original value. If either operation results in None, returns None.

Example:

result := OptionMonadChainFirst(OptionSome(5), func(x int) Option[string] {
    return OptionSome(fmt.Sprintf("%d", x))
}) // OptionSome(5) - original value is kept

func OptionMonadChainTo added in v2.3.120

func OptionMonadChainTo[A, B any](ma Option[A], mb Option[B]) Option[B]

OptionMonadChainTo ignores the first Option and returns the second Option. Useful for sequencing operations where the first result is not needed.

Example:

result := OptionMonadChainTo(OptionSome(5), OptionSome("hello")) // OptionSome("hello")

func OptionMonadFlap added in v2.3.120

func OptionMonadFlap[B, A any](fab Option[func(A) B], a A) Option[B]

OptionMonadFlap applies a value to a function wrapped in an Option. This is the monadic form of Flap.

Example:

fab := OptionSome(N.Mul(2))
result := OptionMonadFlap(fab, 5) // OptionSome(10)

func OptionMonadMap added in v2.3.120

func OptionMonadMap[A, B any](fa Option[A], f func(A) B) Option[B]

OptionMonadMap applies a function to the value inside an Option. If the Option is None, returns None. This is the monadic form of Map.

Example:

fa := OptionSome(5)
result := OptionMonadMap(fa, N.Mul(2)) // OptionSome(10)

func OptionMonadMapTo added in v2.3.120

func OptionMonadMapTo[A, B any](fa Option[A], b B) Option[B]

OptionMonadMapTo replaces the value inside an Option with a constant value. If the Option is None, returns None. This is the monadic form of MapTo.

Example:

fa := OptionSome(5)
result := OptionMonadMapTo(fa, "hello") // OptionSome("hello")

func OptionMonadSequence2 added in v2.3.120

func OptionMonadSequence2[T1, T2, R any](o1 Option[T1], o2 Option[T2], f func(T1, T2) Option[R]) Option[R]

OptionMonadSequence2 sequences two Options and applies a function to their values. Returns None if either Option is None.

Example:

result := OptionMonadSequence2(OptionSome(2), OptionSome(3), func(a, b int) Option[int] {
    return OptionSome(a + b)
}) // OptionSome(5)

func OptionNone added in v2.3.120

func OptionNone[T any]() Option[T]

OptionNone creates an Option that contains no value.

Example:

opt := OptionNone[int]() // Empty Option of type int
opt := OptionNone[string]() // Empty Option of type string

func OptionOf added in v2.3.120

func OptionOf[T any](value T) Option[T]

OptionOf creates an Option that contains a value. This is an alias for OptionSome and is used in monadic contexts.

Example:

opt := OptionOf(42) // Option containing 42

func OptionSequenceArray added in v2.3.120

func OptionSequenceArray[A any](ma []Option[A]) Option[[]A]

OptionSequenceArray converts an array of Options into an Option of an array. Returns Some containing all values if all Options are Some, None if any is None.

Example:

result := OptionSequenceArray(A.From(OptionSome(1), OptionSome(2), OptionSome(3))) // OptionSome([1, 2, 3])
result := OptionSequenceArray(A.From(OptionSome(1), OptionNone[int](), OptionSome(3))) // None

func OptionSequenceArrayG added in v2.3.120

func OptionSequenceArrayG[GA ~[]A, GOA ~[]Option[A], A any](ma GOA) Option[GA]

OptionSequenceArrayG converts an array of Options into an Option of an array. Returns Some containing all values if all Options are Some, None if any is None. This is the generic version that works with custom slice types.

Example:

type MySlice []int
result := OptionSequenceArrayG[MySlice](A.From(OptionSome(1), OptionSome(2))) // OptionSome(MySlice{1, 2})
result := OptionSequenceArrayG[MySlice](A.From(OptionSome(1), OptionNone[int]())) // None

func OptionSome added in v2.3.120

func OptionSome[T any](value T) Option[T]

OptionSome creates an Option that contains a value.

Example:

opt := OptionSome(42) // Option containing 42
opt := OptionSome("hello") // Option containing "hello"

func OptionToAny added in v2.3.120

func OptionToAny[T any](src T) Option[any]

OptionToAny converts a value of any type to Option[any]. This always succeeds and returns Some containing the value as any.

Example:

result := OptionToAny(42) // Some(any(42))
result := OptionToAny("hello") // Some(any("hello"))

func OptionTryCatch added in v2.3.120

func OptionTryCatch[A any](f func() (A, error)) Option[A]

OptionTryCatch executes a function that may return an error and converts the result to an Option. Returns OptionSome(value) if no error occurred, None if an error occurred.

Example:

result := OptionTryCatch(func() (int, error) {
    return strconv.Atoi("42")
}) // OptionSome(42)

func OptionZero added in v2.3.120

func OptionZero[A any]() Option[A]

OptionZero returns the zero value of an Option, which is None. This function is useful as an identity element in monoid operations or for creating an empty Option.

The zero value for Option[A] is always None, representing the absence of a value. This is consistent with the Option monad's semantics where None represents "no value" and Some represents "a value".

Important: OptionZero() returns the same value as the default initialization of Option[A]. When you declare `var o Option[A]` without initialization, it has the same value as OptionZero[A]().

Note: Unlike other types where zero might be a default value, Option's zero is explicitly the absence of any value (None), not Some with a zero value.

Example:

// OptionZero Option of any type is always None
o1 := option.OptionZero[int]()     // None
o2 := option.OptionZero[string]()  // None
o3 := option.OptionZero[*int]()    // None

// OptionZero equals default initialization
var defaultInit Option[int]
zero := option.OptionZero[int]()
assert.Equal(t, defaultInit, zero) // true

// Verify it's None
o := option.OptionZero[int]()
assert.True(t, option.IsNone(o))   // true
assert.False(t, option.IsOptionSome(o))  // false

// Different from Some with zero value
someZero := option.OptionSome(0)         // OptionSome(0)
zero := option.OptionZero[int]()         // None
assert.NotEqual(t, someZero, zero) // they are different

func (Option[A]) Format added in v2.3.120

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

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

  • %s, %v, %+v, %q, and all other verbs: uses String() representation

The exact output format is not a stable contract and may change across versions.

func (Option[A]) LogValue added in v2.3.120

func (s Option[A]) LogValue() slog.Value

func (Option[A]) MarshalJSON added in v2.3.120

func (s Option[A]) MarshalJSON() ([]byte, error)

func (Option[A]) String added in v2.3.120

func (s Option[A]) String() string

String implements fmt.Stringer for Option. Returns a human-readable string representation intended for debugging and logging. The exact format, including any package-path prefix that appears in %T output, is not a stable contract and may change across versions.

Example:

Some(42).String() // "Some[int](42)"
None[int]().String() // "None[int]"

func (*Option[A]) UnmarshalJSON added in v2.3.120

func (s *Option[A]) UnmarshalJSON(data []byte) error

type OptionKleisli added in v2.3.120

type OptionKleisli[A, B any] = func(A) Option[B]

func OptionFromNonZero added in v2.3.120

func OptionFromNonZero[A comparable]() OptionKleisli[A, A]

func OptionFromPredicate added in v2.3.120

func OptionFromPredicate[A any](pred Predicate[A]) OptionKleisli[A, A]

OptionFromPredicate returns a function that creates an Option based on a predicate. The returned function will wrap a value in Some if the predicate is satisfied, otherwise None.

Example:

isPositive := OptionFromPredicate(N.MoreThan(0))
result := isPositive(5)  // OptionSome(5)
result := isPositive(-1) // None

func OptionFromValidation added in v2.3.120

func OptionFromValidation[A, B any](f func(A) (B, bool)) OptionKleisli[A, B]

OptionFromValidation converts a validation function (returning value and bool) to an Option-returning function. This is an alias for Optionize1.

Example:

parseNum := OptionFromValidation(func(s string) (int, bool) {
    n, err := strconv.Atoi(s)
    return n, err == nil
})
result := parseNum("42") // OptionSome(42)

func OptionFromZero added in v2.3.120

func OptionFromZero[A comparable]() OptionKleisli[A, A]

func OptionOptionize1 added in v2.3.120

func OptionOptionize1[F ~func(T0) (R, bool), T0, R any](f F) OptionKleisli[T0, R]

OptionOptionize1 converts a function with 1 parameters returning a tuple of a return value R and a boolean into a function with 1 parameters returning an Option[R]

func OptionTraverseArray added in v2.3.120

func OptionTraverseArray[A, B any](f OptionKleisli[A, B]) OptionKleisli[[]A, []B]

OptionTraverseArray transforms an array by applying a function that returns an Option to each element. Returns Some containing the array of results if all operations succeed, None if any fails.

Example:

validate := F.Flow2(Predicate(N.MoreThan(0)), Map(N.Mul(2)))
result := OptionTraverseArray(validate)([]int{1, 2, 3}) // OptionSome([2, 4, 6])
result := OptionTraverseArray(validate)([]int{1, -1, 3}) // None

func OptionTraverseArrayG added in v2.3.120

func OptionTraverseArrayG[GA ~[]A, GB ~[]B, A, B any](f OptionKleisli[A, B]) OptionKleisli[GA, GB]

OptionTraverseArrayG transforms an array by applying a function that returns an Option to each element. Returns Some containing the array of results if all operations succeed, None if any fails. This is the generic version that works with custom slice types.

Example:

parse := func(s string) Option[int] {
    n, err := strconv.Atoi(s)
    if err != nil { return OptionNone[int]() }
    return OptionSome(n)
}
result := OptionTraverseArrayG[[]string, []int](parse)([]string{"1", "2", "3"}) // OptionSome([1, 2, 3])
result := OptionTraverseArrayG[[]string, []int](parse)([]string{"1", "x", "3"}) // None

func OptionTraverseArrayWithIndex added in v2.3.120

func OptionTraverseArrayWithIndex[A, B any](f func(int, A) Option[B]) OptionKleisli[[]A, []B]

OptionTraverseArrayWithIndex transforms an array by applying an indexed function that returns an Option. The function receives both the index and the element.

Example:

f := func(i int, x int) Option[int] {
    if x > i { return OptionSome(x) }
    return OptionNone[int]()
}
result := OptionTraverseArrayWithIndex(f)([]int{1, 2, 3}) // OptionSome([1, 2, 3])

func OptionTraverseArrayWithIndexG added in v2.3.120

func OptionTraverseArrayWithIndexG[GA ~[]A, GB ~[]B, A, B any](f func(int, A) Option[B]) OptionKleisli[GA, GB]

OptionTraverseArrayWithIndexG transforms an array by applying an indexed function that returns an Option. The function receives both the index and the element. This is the generic version that works with custom slice types.

Example:

f := func(i int, s string) Option[string] {
    return OptionSome(fmt.Sprintf("%d:%s", i, s))
}
result := OptionTraverseArrayWithIndexG[[]string, []string](f)([]string{"a", "b"}) // OptionSome(["0:a", "1:b"])

type OptionKleisliI added in v2.3.120

type OptionKleisliI[A, B any] = func(A) (B, bool)

type OptionOperator added in v2.3.120

type OptionOperator[A, B any] = OptionKleisli[Option[A], B]

func OptionAlt added in v2.3.120

func OptionAlt[A any](that func() Option[A]) OptionOperator[A, A]

OptionAlt returns a function that provides an alternative Option if the input is None.

Example:

withDefault := OptionAlt(func() Option[int] { return OptionSome(0) })
result := withDefault(OptionSome(5)) // OptionSome(5)
result := withDefault(OptionNone[int]()) // OptionSome(0)

func OptionAp added in v2.3.120

func OptionAp[B, A any](fa Option[A]) OptionOperator[func(A) B, B]

OptionAp is the curried applicative functor for Option. Returns a function that applies an Option-wrapped function to the given Option value.

Example:

fa := OptionSome(5)
applyTo5 := OptionAp[int](fa)
fab := OptionSome(N.Mul(2))
result := applyTo5(fab) // OptionSome(10)

func OptionChain added in v2.3.120

func OptionChain[A, B any](f OptionKleisli[A, B]) OptionOperator[A, B]

OptionChain returns a function that applies an Option-returning function to an Option value. This is the curried form of the monadic bind operation.

Example:

validate := OptionChain(F.Flow2(Predicate(N.MoreThan(0)), Map(N.Mul(2))))
result := validate(OptionSome(5)) // OptionSome(10)

func OptionChainFirst added in v2.3.120

func OptionChainFirst[A, B any](f OptionKleisli[A, B]) OptionOperator[A, A]

OptionChainFirst returns a function that applies an Option-returning function but keeps the original value.

Example:

logAndKeep := OptionChainFirst(func(x int) Option[string] {
    fmt.Println(x)
    return OptionSome("logged")
})
result := logAndKeep(OptionSome(5)) // OptionSome(5)

func OptionChainOptionNone added in v2.3.120

func OptionChainOptionNone[A any](onNone func() Option[A]) OptionOperator[A, A]

ChainNone is the curried version that sequences a computation on the None (empty) value. Returns a function that applies the provided function when the Option is None, or returns None when the Option is Some.

Note: ChainNone is identical to Alt - both provide the same functionality for providing alternative values when an Option is None.

The naming convention follows the pattern established by ChainLeft in the Either type, where operations on the "error" or "empty" case use the Left/None suffix to distinguish them from operations on the "success" or "present" case (Chain operates on Some values, while ChainNone operates on None values).

This is useful for creating reusable default value providers or transformers that can be composed with other Option operations using pipes or function composition.

Example:

// Create a reusable default provider
provideDefault := option.ChainNone(func() option.Option[int] {
    return option.OptionSome(42)
})

// Use in a pipeline
result := F.Pipe1(
    option.OptionNone[int](),
    provideDefault,
) // OptionSome(42)

// Some values pass through unchanged
result := F.Pipe1(
    option.OptionSome(10),
    provideDefault,
) // OptionSome(10)

func OptionChainTo added in v2.3.120

func OptionChainTo[A, B any](mb Option[B]) OptionOperator[A, B]

OptionChainTo returns a function that ignores its input Option and returns a fixed Option.

Example:

replaceWith := OptionChainTo(OptionSome("hello"))
result := replaceWith(OptionSome(42)) // OptionSome("hello")

func OptionFilter added in v2.3.120

func OptionFilter[A any](pred Predicate[A]) OptionOperator[A, A]

OptionFilter keeps the Option if it's Some and the predicate is satisfied, otherwise returns None.

Example:

isPositive := OptionFilter(N.MoreThan(0))
result := isPositive(OptionSome(5)) // OptionSome(5)
result := isPositive(OptionSome(-1)) // None
result := isPositive(OptionNone[int]()) // None

func OptionFlap added in v2.3.120

func OptionFlap[B, A any](a A) OptionOperator[func(A) B, B]

OptionFlap returns a function that applies a value to an Option-wrapped function.

Example:

applyFive := OptionFlap[int](5)
fab := OptionSome(N.Mul(2))
result := applyFive(fab) // OptionSome(10)

func OptionMap added in v2.3.120

func OptionMap[A, B any](f func(a A) B) OptionOperator[A, B]

OptionMap returns a function that applies a transformation to the value inside an Option. If the Option is None, returns None.

Example:

double := OptionMap(N.Mul(2))
result := double(OptionSome(5)) // OptionSome(10)
result := double(OptionNone[int]()) // None

func OptionMapTo added in v2.3.120

func OptionMapTo[A, B any](b B) OptionOperator[A, B]

OptionMapTo returns a function that replaces the value inside an Option with a constant.

Example:

replaceWith42 := OptionMapTo[string, int](42)
result := replaceWith42(OptionSome("hello")) // OptionSome(42)

type OptionTraversable added in v2.3.120

type OptionTraversable[A, B, GA, GB any] = func(OptionKleisli[A, B]) OptionKleisli[GA, GB]

OptionTraversable represents a data structure that can be traversed from left to right, applying an effectful function to each element and collecting the results.

A Traversable takes a Kleisli arrow (a function that returns an Option) and produces another Kleisli arrow that operates on a container of values.

Type Parameters:

  • A: The input element type
  • B: The output element type
  • GA: The input container type (e.g., []A, map[K]A)
  • GB: The output container type (e.g., []B, map[K]B)

The Traversable signature:

func(Kleisli[A, B]) Kleisli[GA, GB]

expands to:

func(func(A) Option[B]) func(GA) Option[GB]

This means: given a function that transforms A to Option[B], produce a function that transforms a container of A values into an Option of a container of B values.

Behavior:

  • If all transformations succeed (return Some), the result is Some containing the container of all transformed values
  • If any transformation fails (returns None), the entire result is None

Common Use Cases:

  • Validating and transforming collections where any failure should fail the whole operation
  • Parsing collections of strings where all must parse successfully
  • Applying optional transformations across data structures

Example:

// Array traversable
traversable := TraversableArray[string, int]()
parse := func(s string) Option[int] {
    n, err := strconv.Atoi(s)
    if err != nil { return None[int]() }
    return Some(n)
}
result := traversable(parse)([]string{"1", "2", "3"}) // Some([1, 2, 3])
result := traversable(parse)([]string{"1", "x", "3"}) // None

See Also:

  • TraversableArray: Traversable instance for arrays
  • TraverseArray: Direct array traversal function
  • TraverseRecord: Traversal for maps/records

func OptionTraversableArray added in v2.3.120

func OptionTraversableArray[A, B any]() OptionTraversable[A, B, []A, []B]

OptionTraversableArray returns a Traversable instance for arrays. A Traversable represents a data structure that can be traversed from left to right, applying an effectful function to each element and collecting the results.

This function provides a way to obtain the traversal operation for arrays as a first-class value, which is useful when you need to pass the traversal operation as a parameter or compose it with other operations.

Type Parameters:

  • A: The input element type
  • B: The output element type

Returns:

  • Traversable[A, B, []A, []B]: A function that takes a Kleisli arrow and returns another Kleisli arrow that operates on arrays

The returned Traversable has the signature:

func(OptionKleisli[A, B]) OptionKleisli[[]A, []B]

which is equivalent to:

func(func(A) Option[B]) func([]A) Option[[]B]

Example:

// Get the traversable instance
traversable := OptionTraversableArray[string, int]()

// Use it with a parsing function
parse := func(s string) Option[int] {
    n, err := strconv.Atoi(s)
    if err != nil { return OptionNone[int]() }
    return OptionSome(n)
}
result := traversable(parse)([]string{"1", "2", "3"}) // OptionSome([1, 2, 3])

See Also:

  • TraverseArray: Direct traversal without obtaining the Traversable instance
  • TraverseArrayG: Generic version supporting custom slice types

type Optional

type Optional[S, A any] struct {
	GetOption func(s S) Option[A]
	Set       func(a A) EM.Endomorphism[S]
	// contains filtered or unexported fields
}

Optional is an optional reference to a subpart of a data type

func LensAsOptional added in v2.3.122

func LensAsOptional[S, A any](sa Lens[S, A]) Optional[S, A]

LensAsOptional converts a Lens into an Optional

func MakeOptional

func MakeOptional[S, A any](get OptionKleisli[S, A], set func(S, A) S) Optional[S, A]

MakeOptional creates an Optional based on a getter and a setter function. Make sure that the setter creates a (shallow) copy of the data. This happens automatically if the data is passed by value. For pointers consider to use `MakeOptionalRef` and for other kinds of data structures that are copied by reference make sure the setter creates the copy.

func MakeOptionalCurried

func MakeOptionalCurried[S, A any](get OptionKleisli[S, A], set func(A) func(S) S) Optional[S, A]

func MakeOptionalCurriedWithName

func MakeOptionalCurriedWithName[S, A any](get OptionKleisli[S, A], set func(A) func(S) S, name string) Optional[S, A]

func MakeOptionalRef

func MakeOptionalRef[S, A any](get OptionKleisli[*S, A], set func(*S, A) *S) Optional[*S, A]

MakeOptionalRef creates an Optional based on a getter and a setter function. The setter passed in does not have to create a shallow copy, the implementation wraps the setter into one that copies the pointer before modifying it

func MakeOptionalRefCurriedWithName

func MakeOptionalRefCurriedWithName[S, A any](get OptionKleisli[*S, A], set func(A) func(*S) *S, name string) Optional[*S, A]

func MakeOptionalRefWithName

func MakeOptionalRefWithName[S, A any](get OptionKleisli[*S, A], set func(*S, A) *S, name string) Optional[*S, A]

func MakeOptionalWithName

func MakeOptionalWithName[S, A any](get OptionKleisli[S, A], set func(S, A) S, name string) Optional[S, A]

func OptionalId

func OptionalId[S any]() Optional[S, S]

OptionalId returns am optional implementing the identity operation

func OptionalIdRef

func OptionalIdRef[S any]() Optional[*S, *S]

Id returns am optional implementing the identity operation

func OptionalSome added in v2.3.122

func OptionalSome[S, A any](soa Optional[S, Option[A]]) Optional[S, A]

OptionalSome creates an Optional that focuses on the OptionalSome variant of an Option within a structure.

Given an Optional[S, Option[A]] that focuses on an Option field, this function returns an Optional[S, A] that focuses directly on the value within OptionalSome.

This is useful when you have a structure containing an Option field and want to work with the value inside OptionalSome without manually unwrapping the Option.

The conversion works by composing the provided optional with a prism that extracts values from OptionalSome. The resulting optional:

  • Returns OptionalSome(a) from GetOption only when both the outer optional matches and the inner Option is OptionalSome
  • Performs Set only when both conditions are met (no-op otherwise)

The resulting Optional satisfies the three optional laws:

  1. GetSet Law (No-op on None): If GetOption(s) returns None (either because the outer optional doesn't match or the inner Option is None), then Set(a)(s) returns s unchanged.

    Formally: GetOption(s) = None => Set(a)(s) = s

  2. SetGet Law (Get what you Set): If GetOption(s) returns OptionalSome(_), then GetOption(Set(a)(s)) returns OptionalSome(a).

    Formally: GetOption(s) = OptionalSome(_) => GetOption(Set(a)(s)) = OptionalSome(a)

  3. SetSet Law (Last Set Wins): Set(b)(Set(a)(s)) equals Set(b)(s).

    Formally: Set(b)(Set(a)(s)) = Set(b)(s)

Type Parameters:

  • S: The structure type
  • A: The type of value within the Option

Parameters:

  • soa: An optional focusing on an Option[A] field within S

Returns:

  • An Optional[S, A] that focuses directly on values within OptionalSome

Example:

type Config struct {
    Timeout Option[int]
}

// Create an optional for the Timeout field
timeoutOptional := optional.MakeOptional(
    func(c Config) Option[Option[int]] {
        return OptionalSome(c.Timeout)
    },
    func(c Config, opt Option[int]) Config {
        c.Timeout = opt
        return c
    },
)

// Focus on the value within OptionalSome
valueOptional := OptionalSome(timeoutOptional)

// Use the optional
config := Config{Timeout: OptionalSome(30)}
value := valueOptional.GetOption(config)  // OptionalSome(30)
updated := valueOptional.Set(60)(config)  // Config{Timeout: OptionalSome(60)}

// Set is no-op when inner Option is None (Law 1)
emptyConfig := Config{Timeout: None[int]()}
unchanged := valueOptional.Set(60)(emptyConfig)  // emptyConfig (unchanged)

See Also:

  • AsOptional: Converts prisms to optionals
  • PrismSome: The underlying prism for Option types
  • github.com/IBM/fp-go/v2/optics/optional.Compose for composing optionals

func PrismAsOptional added in v2.3.122

func PrismAsOptional[S, A any](sa Prism[S, A]) Optional[S, A]

PrismAsOptional converts a Prism into an Optional.

A Prism[S, A] focuses on a specific variant within a sum type S, providing:

  • GetOption: Attempts to extract A from S (returns Option[A])
  • ReverseGet: Constructs S from A (always succeeds)

An Optional[S, A] focuses on a value that may not exist within S, providing:

  • GetOption: Attempts to extract A from S (returns Option[A])
  • Set: Updates A within S if it exists (no-op if it doesn't)

The conversion works by:

  • Using the prism's GetOption directly as the optional's GetOption
  • Implementing Set using the prism's Set operation, which internally uses GetOption to check if the value exists before updating

The resulting Optional satisfies the three optional laws:

  1. GetSet Law (No-op on None): If GetOption(s) returns None, then Set(a)(s) returns s unchanged. This is satisfied because the prism's Set operation checks GetOption and only updates when it returns Some.

    Formally: GetOption(s) = None => Set(a)(s) = s

  2. SetGet Law (Get what you Set): If GetOption(s) returns Some(_), then GetOption(Set(a)(s)) returns Some(a). This is satisfied because the prism's Set operation replaces the focused value with the new value when GetOption returns Some.

    Formally: GetOption(s) = Some(_) => GetOption(Set(a)(s)) = Some(a)

  3. SetSet Law (Last Set Wins): Set(b)(Set(a)(s)) equals Set(b)(s). This is satisfied because both operations check GetOption and only update when it returns Some, with the prism's Set operation ensuring the last set wins.

    Formally: Set(b)(Set(a)(s)) = Set(b)(s)

Type Parameters:

  • S: The source type (sum type)
  • A: The focus type (variant within the sum type)

Parameters:

  • sa: A prism focusing on variant A within sum type S

Returns:

  • An Optional[S, A] that focuses on the same variant

Example:

type Result interface{ isResult() }
type Success struct{ Value int }
type Failure struct{ Error string }

// Create a prism for the Success variant
successPrism := prism.MakePrism(
    func(r Result) Option[int] {
        if s, ok := r.(Success); ok {
            return Some(s.Value)
        }
        return None[int]()
    },
    func(v int) Result { return Success{Value: v} },
)

// Convert to optional
successOptional := PrismAsOptional(successPrism)

// Use the optional
result := Success{Value: 42}
value := successOptional.GetOption(result)  // Some(42)
updated := successOptional.Set(100)(result) // Success{Value: 100}

// Set is no-op when GetOption returns None (Law 1)
failure := Failure{Error: "failed"}
unchanged := successOptional.Set(100)(failure) // failure (unchanged)

See Also:

  • Some: Focuses on the Some variant of Option types
  • github.com/IBM/fp-go/v2/optics/prism for prism operations
  • github.com/IBM/fp-go/v2/optics/optional for optional operations

func (Optional[S, A]) Compose

func (p Optional[S, A]) Compose[B any](ab Optional[A, B]) Optional[S, B]

Compose returns a new Optional that focuses deeper into a structure by chaining this optional (S → A) with an inner optional (A → B), producing a composed optional (S → B).

This is the method-receiver form of the package-level OptionalComposeOptional function, available only on Go 1.27 and later because Go did not support type parameters on methods before that version. On earlier toolchains, use the equivalent free function instead:

// method form (go1.27+)
composed := outerOptional.Compose(innerOptional)

// free-function form (all versions)
composed := optional.Compose[S](innerOptional)(outerOptional)

GetOption of the composed optional chains the two GetOption functions: it first applies the outer optional to obtain an Option[A], then chains the inner optional through that option via O.Chain, returning None whenever either optional produces None.

Set of the composed optional updates the deeply nested focus by threading the new value back through the inner optional's Set and then propagating the change upward via the outer optional's Set. When either optional produces None, Set is a no-op and the original S is returned unchanged, consistent with the Optional no-op law.

The composed optional satisfies all three optional laws (GetSet, SetGet, SetSet) whenever both constituent optionals individually satisfy them.

Type Parameters:

  • B: the focus type of the inner optional and of the resulting optional

Parameters:

  • ab: the inner optional from A to B

Returns:

  • Optional[S, B]: a new optional from S directly to B

See Also:

  • Compose: the equivalent package-level function
  • ComposeRef: variant for pointer-based outer structures

func (Optional[S, A]) ComposeLens added in v2.3.122

func (l Optional[S, A]) ComposeLens[B any](ab Lens[A, B]) Optional[S, B]

ComposeLens returns a new Optional that focuses deeper into a structure by composing this optional (S → A) with a lens (A → B), producing an optional (S → B).

Because a Lens always succeeds, the resulting Optional inherits its partiality exclusively from the outer optional: GetOption returns None only when this optional produces None; Set is a no-op only in that same case.

This is the method-receiver form of the package-level OptionalComposeLens function, available only on Go 1.27 and later because Go did not support type parameters on methods before that version. On earlier toolchains, use the equivalent free function instead:

// method form (go1.27+)
composed := outerOptional.ComposeLens(innerLens)

// free-function form (all versions)
composed := OptionalComposeLens[S](innerLens)(outerOptional)

GetOption of the composed optional applies this optional's GetOption to obtain an Option[A], then – when Some – applies the lens's Get to retrieve B, returning None whenever this optional produces None.

Set of the composed optional updates the deeply nested focus: it uses the lens's Set to embed the new B back into A, then propagates the updated A upward via this optional's Set. When this optional produces None, Set is a no-op and the original S is returned unchanged, consistent with the Optional no-op law.

The composed optional satisfies all three optional laws (GetSet, SetGet, SetSet) whenever this optional individually satisfies them (the lens laws are always satisfied by a well-formed Lens).

Type Parameters:

  • B: the focus type of the inner lens and of the resulting optional

Parameters:

  • ab: the inner lens from A to B

Returns:

  • Optional[S, B]: a new optional from S directly to B

See Also:

  • Compose: variant that composes with an Optional[A, B] instead of a Lens
  • OptionalComposeLens: the equivalent package-level function

func (Optional[S, A]) ComposePrism added in v2.3.122

func (l Optional[S, A]) ComposePrism[B any](ab Prism[A, B]) Optional[S, B]

ComposePrism returns a new Optional that focuses deeper into a structure by composing this optional (S → A) with a prism (A → B), producing an optional (S → B).

Because a Prism may not match its input, the resulting Optional is None whenever either this optional produces None or the prism does not match the focused A value. Set is a no-op in both cases.

This is the method-receiver form of the package-level OptionalComposePrism function, available only on Go 1.27 and later because Go did not support type parameters on methods before that version. On earlier toolchains, use the equivalent free function instead:

// method form (go1.27+)
composed := outerOptional.ComposePrism(innerPrism)

// free-function form (all versions)
composed := OptionalComposePrism[S](innerPrism)(outerOptional)

GetOption of the composed optional first applies this optional's GetOption to obtain an Option[A]; when Some, it applies the prism's GetOption to try to extract B from A. None is returned whenever either step fails.

Set of the composed optional checks whether GetOption would return Some before writing: when it would, it uses the prism's ReverseGet to reconstruct an A from the new B, then propagates the updated A upward via this optional's Set. When GetOption returns None (either because this optional misses or because the prism does not match), Set is a no-op and the original S is returned unchanged, consistent with the Optional no-op law.

The composed optional satisfies all three optional laws (GetSet, SetGet, SetSet) whenever both this optional and the prism individually satisfy their respective laws.

Type Parameters:

  • B: the focus type of the prism and of the resulting optional

Parameters:

  • ab: the prism from A to B

Returns:

  • Optional[S, B]: a new optional from S directly to B

See Also:

  • Compose: variant that composes with an Optional[A, B] instead of a Prism
  • ComposeLens: variant that composes with a Lens[A, B] instead of a Prism
  • OptionalComposePrism: the equivalent package-level function

func (Optional) Format

func (o Optional) Format(f fmt.State, c rune)

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

  • %s, %v, %+v, %q, and all other verbs: uses String() representation (optional name)

The exact output format is not a stable contract and may change across versions.

func (Optional) LogValue

func (o Optional) LogValue() slog.Value

func (Optional) String

func (o Optional) String() string

String returns the name of the optional for debugging and display purposes. The exact format is not a stable contract and may change across versions.

Example:

fieldOptional := optional.MakeOptionalWithName(..., "Person.Email")
fmt.Println(fieldOptional)  // Prints: "Person.Email"

type OptionalKleisli

type OptionalKleisli[S, A, B any] = func(A) Optional[S, B]

OptionalKleisli represents a function that takes a value of type A and returns an Optional[S, B]. This is commonly used for composing optionals in a monadic style.

Type Parameters:

  • S: The source type of the resulting optional
  • A: The input type to the function
  • B: The focus type of the resulting optional

type OptionalOperator

type OptionalOperator[S, A, B any] = func(Optional[S, A]) Optional[S, B]

OptionalOperator represents a function that transforms one optional into another. It takes an Optional[S, A] and returns an Optional[S, B], allowing for optional transformations.

Type Parameters:

  • S: The source type (remains constant)
  • A: The original focus type
  • B: The new focus type

func OptionalComposeLens added in v2.3.122

func OptionalComposeLens[S, A, B any](ab Lens[A, B]) OptionalOperator[S, A, B]

LensComposeOptional composes a lens with an optional

func OptionalComposeOptional

func OptionalComposeOptional[S, A, B any](ab Optional[A, B]) OptionalOperator[S, A, B]

OptionalComposeOptional combines two Optional and allows to narrow down the focus to a sub-Optional

func OptionalComposeOptionalRef

func OptionalComposeOptionalRef[S, A, B any](ab Optional[A, B]) OptionalOperator[*S, A, B]

OptionalComposeOptionalRef combines two Optional and allows to narrow down the focus to a sub-Optional

func OptionalComposePrism added in v2.3.122

func OptionalComposePrism[S, A, B any](ab Prism[A, B]) OptionalOperator[S, A, B]

OptionalComposePrism composes an Optional with a Prism to create a new Optional.

This composition allows you to first focus on a value that may not exist (using an Optional), and then focus on a variant within that value (using a Prism). The result is an Optional because either the initial optional may not match, or the prism may not match the focused value.

The composition works by:

  1. Converting the Prism to an Optional using AsOptional
  2. Composing the input Optional with the prism-derived Optional using optional composition

The resulting Optional satisfies the three optional laws:

  1. GetSet Law (No-op on None): If GetOption(s) returns None (either the optional doesn't match or the prism doesn't match), then Set(b)(s) returns s unchanged. This is satisfied because both the optional and prism-to-optional conversions ensure Set is a no-op when GetOption returns None.

    Formally: GetOption(s) = None => Set(b)(s) = s

  2. SetGet Law (Get what you Set): If GetOption(s) returns Some(_) (both optional and prism match), then GetOption(Set(b)(s)) returns Some(b). This is satisfied because optional composition preserves this property from both components.

    Formally: GetOption(s) = Some(_) => GetOption(Set(b)(s)) = Some(b)

  3. SetSet Law (Last Set Wins): Set(c)(Set(b)(s)) equals Set(c)(s). This is satisfied because optional composition preserves this property.

    Formally: Set(c)(Set(b)(s)) = Set(c)(s)

Type Parameters:

  • S: The source type
  • A: The intermediate type (focused by the Optional)
  • B: The target type (variant within A, focused by the Prism)

Parameters:

  • ab: A Prism[A, B] that focuses on variant B within type A

Returns:

  • A function that takes an Optional[S, A] and returns an Optional[S, B]

Example:

type Config struct {
    Database Option[DatabaseConfig]
}

type DatabaseConfig interface{ isDatabase() }
type PostgreSQL struct{ Host string }
type MySQL struct{ Host string }

// Optional focusing on Database field
dbOptional := optional.MakeOptional(
    func(c Config) Option[DatabaseConfig] {
        return c.Database
    },
    func(c Config, db DatabaseConfig) Config {
        c.Database = Some(db)
        return c
    },
)

// Prism focusing on PostgreSQL variant
pgPrism := prism.MakePrism(
    func(db DatabaseConfig) Option[PostgreSQL] {
        if pg, ok := db.(PostgreSQL); ok {
            return Some(pg)
        }
        return None[PostgreSQL]()
    },
    func(pg PostgreSQL) DatabaseConfig { return pg },
)

// OptionalComposePrism to create Optional[Config, PostgreSQL]
configPgOptional := OptionalComposePrism[Config, DatabaseConfig, PostgreSQL](pgPrism)(dbOptional)

// Use the optional
config := Config{Database: Some(PostgreSQL{Host: "localhost"})}
host := configPgOptional.GetOption(config)  // Some(PostgreSQL{Host: "localhost"})
updated := configPgOptional.Set(PostgreSQL{Host: "remote"})(config)
// updated.Database = Some(PostgreSQL{Host: "remote"})

// Set is no-op when optional doesn't match (Law 1)
emptyConfig := Config{Database: None[DatabaseConfig]()}
unchanged := configPgOptional.Set(PostgreSQL{Host: "remote"})(emptyConfig)
// unchanged == emptyConfig (no-op)

// Set is no-op when prism doesn't match (Law 1)
mysqlConfig := Config{Database: Some(MySQL{Host: "localhost"})}
unchanged = configPgOptional.Set(PostgreSQL{Host: "remote"})(mysqlConfig)
// unchanged == mysqlConfig (no-op)

See Also:

  • AsOptional: Converts prisms to optionals
  • github.com/IBM/fp-go/v2/optics/optional.OptionalComposePrism for optional composition
  • github.com/IBM/fp-go/v2/optics/prism/lens for the inverse composition (prism then lens)

func OptionalIChain

func OptionalIChain[S, A, B any](ab OptionKleisli[A, B], ba OptionKleisli[B, A]) OptionalOperator[S, A, B]

OptionalIChain implements a bidirectional mapping of the transform if the transform can produce optionals (e.g. in case of type mappings)

func OptionalIChainAny

func OptionalIChainAny[S, A any]() OptionalOperator[S, any, A]

OptionalIChainAny implements a bidirectional mapping to and from any

func OptionalIMap

func OptionalIMap[S, A, B any](ab func(A) B, ba func(B) A) OptionalOperator[S, A, B]

OptionalIMap implements a bidirectional mapping of the transform

type Pair added in v2.3.122

type Pair[L, R any] = pair.Pair[L, R]

type Predicate added in v2.3.120

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

func EitherExists added in v2.3.122

func EitherExists[E, T any](p Predicate[T]) Predicate[Either[E, T]]

EitherExists creates a predicate that tests whether an Either value is Right and its value satisfies the given predicate. It returns a function that takes an Either[E, T] and returns true only if the Either is Right and the predicate p returns true for the Right value.

This function is useful for checking if an Either contains a successful value that meets certain criteria, commonly used in filtering operations, validation chains, or conditional logic where you need to verify both the success state and a property of the success value.

The behavior is as follows:

  • If the input is Left, returns false (regardless of the predicate)
  • If the input is Right and p returns true for the Right value, returns true
  • If the input is Right and p returns false for the Right value, returns false

Type Parameters:

  • E: The type of the Left value (error type)
  • T: The type of the Right value (success type)

Parameters:

  • p: A predicate function that tests values of type T

Returns:

A Predicate function that takes an Either[E, T] and returns true if it's Right and satisfies p

Example:

import (
    E "github.com/IBM/fp-go/v2/either"
    N "github.com/IBM/fp-go/v2/number"
)

// Check if Either contains a positive number
isPositive := N.MoreThan(0)
hasPositive := E.EitherExists[string](isPositive)

result1 := hasPositive(E.Right[string](5))
// result1 = true (Right with positive value)

result2 := hasPositive(E.Right[string](-3))
// result2 = false (Right with non-positive value)

result3 := hasPositive(E.Left[int]("error"))
// result3 = false (Left value)

// Use in filtering
values := []E.Either[string, int]{
    E.Right[string](5),
    E.Left[int]("error"),
    E.Right[string](-3),
    E.Right[string](10),
}
hasPositiveValue := func(e E.Either[string, int]) bool {
    return hasPositive(e)
}
// Filter to keep only Eithers with positive Right values
// filtered would contain: [Right(5), Right(10)]

See Also:

  • ExistsLeft: Tests if Either is Left and satisfies a predicate
  • Filter: Converts Right values that fail a predicate to Left

func EitherExistsLeft added in v2.3.122

func EitherExistsLeft[T, E any](p Predicate[E]) Predicate[Either[E, T]]

EitherExistsLeft creates a predicate that tests whether an Either value is Left and its value satisfies the given predicate. It returns a function that takes an Either[E, T] and returns true only if the Either is Left and the predicate p returns true for the Left value.

This function is useful for checking if an Either contains an error value that meets certain criteria, commonly used in error filtering, error categorization, or conditional logic where you need to verify both the error state and a property of the error value.

The behavior is as follows:

  • If the input is Right, returns false (regardless of the predicate)
  • If the input is Left and p returns true for the Left value, returns true
  • If the input is Left and p returns false for the Left value, returns false

Type Parameters:

  • T: The type of the Right value (success type)
  • E: The type of the Left value (error type)

Parameters:

  • p: A predicate function that tests values of type E

Returns:

A Predicate function that takes an Either[E, T] and returns true if it's Left and satisfies p

Example:

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

// Check if Either contains a validation error
isValidationError := func(s string) bool {
    return strings.HasPrefix(s, "validation:")
}
hasValidationError := E.EitherExistsLeft[int](isValidationError)

result1 := hasValidationError(E.Left[int]("validation: invalid input"))
// result1 = true (Left with validation error)

result2 := hasValidationError(E.Left[int]("network: connection failed"))
// result2 = false (Left with non-validation error)

result3 := hasValidationError(E.Right[string](42))
// result3 = false (Right value)

// Use in error categorization
results := []E.Either[string, int]{
    E.Left[int]("validation: empty field"),
    E.Right[string](100),
    E.Left[int]("network: timeout"),
    E.Left[int]("validation: invalid format"),
}
hasValidationErr := func(e E.Either[string, int]) bool {
    return hasValidationError(e)
}
// Filter to find validation errors
// filtered would contain: [Left("validation: empty field"), Left("validation: invalid format")]

See Also:

  • Exists: Tests if Either is Right and satisfies a predicate
  • IsLeft: Tests if Either is Left without checking the value

func EitherForAll added in v2.3.122

func EitherForAll[E, T any](p Predicate[T]) Predicate[Either[E, T]]

EitherForAll creates a predicate that tests whether an Either value is Left or its Right value satisfies the given predicate. It returns a function that takes an Either[E, T] and returns true if the Either is Left (regardless of its value) or if it's Right and the predicate p returns true for the Right value.

This function implements universal quantification over the Either type. In logical terms, it states: "for all values in the Either, the predicate holds" - which is vacuously true for Left values (empty case) and requires the predicate to hold for Right values (non-empty case).

The behavior is as follows:

  • If the input is Left, returns true (vacuous truth - predicate holds for empty case)
  • If the input is Right and p returns true for the Right value, returns true
  • If the input is Right and p returns false for the Right value, returns false

Relationship to Haskell and Category Theory:

In Haskell, this corresponds to the all function for the Either type when viewed as a Foldable:

all :: Foldable t => (a -> Bool) -> t a -> Bool
all p (Right x) = p x
all p (Left _)  = True

From a category theory perspective, Either[E, T] is a coproduct (sum type) in the category of types. EitherForAll implements a natural transformation from predicates on T to predicates on Either[E, T], preserving the logical structure where:

  • The Left case represents the "empty" or "absent" case (like Nothing in Maybe/Option)
  • The Right case represents the "present" case that must satisfy the predicate

This is dual to Exists, which implements existential quantification:

  • EitherForAll: "all elements satisfy p" (true for empty, requires p for non-empty)
  • Exists: "some element satisfies p" (false for empty, requires p for non-empty)

The relationship follows De Morgan's laws:

  • EitherForAll(p) ≡ not(Exists(not(p)))
  • Exists(p) ≡ not(EitherForAll(not(p)))

Type Parameters:

  • E: The type of the Left value (error type)
  • T: The type of the Right value (success type)

Parameters:

  • p: A predicate function that tests values of type T

Returns:

A Predicate function that takes an Either[E, T] and returns true if it's Left or Right with p satisfied

Example:

import (
    E "github.com/IBM/fp-go/v2/either"
    N "github.com/IBM/fp-go/v2/number"
)

// Check if Either is Left or contains a positive number
isPositive := N.MoreThan(0)
allPositive := E.EitherForAll[string](isPositive)

result1 := allPositive(E.Right[string](5))
// result1 = true (Right with positive value satisfies predicate)

result2 := allPositive(E.Right[string](-3))
// result2 = false (Right with non-positive value fails predicate)

result3 := allPositive(E.Left[int]("error"))
// result3 = true (Left is vacuously true - no value to check)

// Use in validation: ensure all successful results meet criteria
values := []E.Either[string, int]{
    E.Right[string](5),
    E.Left[int]("error"),      // Ignored (vacuously true)
    E.Right[string](10),
    E.Right[string](-3),       // Fails validation
}
allValid := func(e E.Either[string, int]) bool {
    return allPositive(e)
}
// Check if all non-error values are positive
// result would be false because Right(-3) fails the predicate

// Contrast with Exists:
hasPositive := E.Exists[string](isPositive)
// hasPositive checks if there EXISTS a Right value satisfying p
// allPositive checks if ALL Right values satisfy p (Left is ignored)

See Also:

  • Exists: Tests if Either is Right and satisfies a predicate (existential quantification)
  • ExistsLeft: Tests if Either is Left and satisfies a predicate
  • Filter: Converts Right values that fail a predicate to Left

func OptionExists added in v2.3.120

func OptionExists[T any](p Predicate[T]) Predicate[Option[T]]

OptionExists creates a predicate that tests whether an Option value is Some and its value satisfies the given predicate. It returns a function that takes an Option[T] and returns true only if the Option is Some and the predicate p returns true for the contained value.

This function is useful for checking if an Option contains a value that meets certain criteria, commonly used in filtering operations, validation chains, or conditional logic where you need to verify both the presence of a value and a property of that value.

The behavior is as follows:

  • If the input is None, returns false (regardless of the predicate)
  • If the input is Some and p returns true for the contained value, returns true
  • If the input is Some and p returns false for the contained value, returns false

Type Parameters:

  • T: The type of the value contained in the Option

Parameters:

  • p: A predicate function that tests values of type T

Returns:

A Predicate function that takes an Option[T] and returns true if it's Some and satisfies p

Example:

import (
    O "github.com/IBM/fp-go/v2/option"
    N "github.com/IBM/fp-go/v2/number"
)

// Check if Option contains a positive number
isPositive := N.MoreThan(0)
hasPositive := O.OptionExists(isPositive)

result1 := hasPositive(O.Some(5))
// result1 = true (Some with positive value)

result2 := hasPositive(O.Some(-3))
// result2 = false (Some with non-positive value)

result3 := hasPositive(O.None[int]())
// result3 = false (None value)

// Use in filtering
values := []O.Option[int]{
    O.Some(5),
    O.None[int](),
    O.Some(-3),
    O.Some(10),
}
hasPositiveValue := func(opt O.Option[int]) bool {
    return hasPositive(opt)
}
// Filter to keep only Options with positive Some values
// filtered would contain: [Some(5), Some(10)]

See Also:

  • Filter: Converts Some values that fail a predicate to None
  • IsSome: Tests if Option is Some without checking the value

func OptionForAll added in v2.3.120

func OptionForAll[T any](p Predicate[T]) Predicate[Option[T]]

OptionForAll creates a predicate that tests whether an Option value is None or its Some value satisfies the given predicate. It returns a function that takes an Option[T] and returns true if the Option is None (regardless of content) or if it's Some and the predicate p returns true for the contained value.

This function implements universal quantification over the Option type. In logical terms, it states: "for all values in the Option, the predicate holds" - which is vacuously true for None values (empty case) and requires the predicate to hold for Some values (non-empty case).

The behavior is as follows:

  • If the input is None, returns true (vacuous truth - predicate holds for empty case)
  • If the input is Some and p returns true for the contained value, returns true
  • If the input is Some and p returns false for the contained value, returns false

Relationship to Haskell and Category Theory:

In Haskell, this corresponds to the all function for the Maybe type when viewed as a Foldable:

all :: Foldable t => (a -> Bool) -> t a -> Bool
all p (Just x)  = p x
all p Nothing   = True

From a category theory perspective, Option[T] is a sum type representing optional values. OptionForAll implements a natural transformation from predicates on T to predicates on Option[T], preserving the logical structure where:

  • The None case represents the "empty" or "absent" case
  • The Some case represents the "present" case that must satisfy the predicate

This is dual to Exists, which implements existential quantification:

  • OptionForAll: "all elements satisfy p" (true for empty, requires p for non-empty)
  • Exists: "some element satisfies p" (false for empty, requires p for non-empty)

The relationship follows De Morgan's laws:

  • OptionForAll(p) ≡ not(Exists(not(p)))
  • Exists(p) ≡ not(OptionForAll(not(p)))

Type Parameters:

  • T: The type of the value contained in the Option

Parameters:

  • p: A predicate function that tests values of type T

Returns:

A Predicate function that takes an Option[T] and returns true if it's None or Some with p satisfied

Example:

import (
    O "github.com/IBM/fp-go/v2/option"
    N "github.com/IBM/fp-go/v2/number"
)

// Check if Option is None or contains a positive number
isPositive := N.MoreThan(0)
allPositive := O.OptionForAll(isPositive)

result1 := allPositive(O.Some(5))
// result1 = true (Some with positive value satisfies predicate)

result2 := allPositive(O.Some(-3))
// result2 = false (Some with non-positive value fails predicate)

result3 := allPositive(O.None[int]())
// result3 = true (None is vacuously true - no value to check)

// Use in validation: ensure all present values meet criteria
values := []O.Option[int]{
    O.Some(5),
    O.None[int](),        // Ignored (vacuously true)
    O.Some(10),
    O.Some(-3),           // Fails validation
}
allValid := true
for _, v := range values {
    if !allPositive(v) {
        allValid = false
        break
    }
}
// allValid would be false because Some(-3) fails the predicate

// Contrast with Exists:
hasPositive := O.Exists(isPositive)
// hasPositive checks if there EXISTS a Some value satisfying p
// allPositive checks if ALL Some values satisfy p (None is ignored)

See Also:

  • Exists: Tests if Option is Some and satisfies a predicate (existential quantification)
  • Filter: Converts Some values that fail a predicate to None
  • IsSome: Tests if Option is Some without checking the value

type Prism

type Prism[S, A any] struct {

	// GetOption attempts to extract a value of type A from S.
	// Returns Some(a) if the extraction succeeds, None otherwise.
	GetOption OptionKleisli[S, A]

	// ReverseGet constructs an S from an A.
	// This operation always succeeds.
	ReverseGet func(A) S
	// contains filtered or unexported fields
}

Prism is an optic used to select part of a sum type (tagged union). It provides two operations:

  • GetOption: Try to extract a value of type A from S (may fail)
  • ReverseGet: Construct an S from an A (always succeeds)

Prisms are useful for working with variant types like Either, Option, or custom sum types where you want to focus on a specific variant.

Type Parameters:

  • S: The source type (sum type)
  • A: The focus type (variant within the sum type)

Example:

type Result interface{ isResult() }
type Success struct{ Value int }
type Failure struct{ Error string }

successPrism := MakePrism(
    func(r Result) Option[int] {
        if s, ok := r.(Success); ok {
            return Some(s.Value)
        }
        return None[int]()
    },
    func(v int) Result { return Success{Value: v} },
)

func MakePrism

func MakePrism[S, A any](get OptionKleisli[S, A], rev func(A) S) Prism[S, A]

MakePrism constructs a Prism from GetOption and ReverseGet functions.

Parameters:

  • get: Function to extract A from S (returns Option[A])
  • rev: Function to construct S from A

Returns:

  • A Prism[S, A] that uses the provided functions

Example:

prism := MakePrism(
    func(opt Option[int]) Option[int] { return opt },
    func(n int) Option[int] { return Some(n) },
)

func MakePrismWithName

func MakePrismWithName[S, A any](get OptionKleisli[S, A], rev func(A) S, name string) Prism[S, A]

func PrismFromOption

func PrismFromOption[T any]() Prism[Option[T], T]

PrismFromOption creates a prism for extracting values from Option types. It provides a safe way to work with Option values, focusing on the Some case and handling the None case gracefully through the prism's GetOption behavior.

The prism's GetOption is the identity function - it returns the Option as-is. If the Option is Some(value), GetOption returns Some(value); if it's None, it returns None. This allows the prism to naturally handle the presence or absence of a value.

The prism's ReverseGet wraps a value into Some, always succeeding.

Type Parameters:

  • T: The value type contained in the Option

Returns:

  • A Prism[Option[T], T] that safely extracts values from Options

Example:

// Create a prism for extracting int values from Option[int]
optPrism := FromOption[int]()

// Extract from Some
someValue := option.Some(42)
result := optPrism.GetOption(someValue)  // Some(42)

// Extract from None
noneValue := option.None[int]()
result = optPrism.GetOption(noneValue)  // None[int]()

// Wrap value into Some
wrapped := optPrism.ReverseGet(100)  // Some(100)

// Use with Set to update Some values
setter := Set[Option[int], int](200)
result := setter(optPrism)(someValue)  // Some(200)
result = setter(optPrism)(noneValue)   // None[int]() (unchanged)

// Compose with other prisms for nested extraction
// Extract int from Option[Option[int]]
nestedPrism := Compose[Option[Option[int]], Option[int], int](
    FromOption[Option[int]](),
    FromOption[int](),
)
nested := option.Some(option.Some(42))
value := nestedPrism.GetOption(nested)  // Some(42)

Common use cases:

  • Extracting values from optional fields
  • Working with nullable data in a type-safe way
  • Composing with other prisms to handle nested Options
  • Filtering and transforming optional values in pipelines
  • Converting between Option and other optional representations

Key insight: This prism treats Option[T] as a "container" that may or may not hold a value of type T. The prism focuses on the value inside, allowing you to work with it when present and gracefully handle its absence when not.

func PrismFromPredicate

func PrismFromPredicate[S any](pred func(S) bool) Prism[S, S]

PrismFromPredicate creates a prism that matches values satisfying a predicate. GetOption returns Some(s) if the predicate is true, None otherwise. ReverseGet is the identity function (doesn't validate the predicate).

Parameters:

  • pred: Predicate function to test values

Returns:

  • A Prism[S, S] that filters based on the predicate

Example:

positivePrism := PrismFromPredicate(N.MoreThan(0))
value := positivePrism.GetOption(42)  // Some(42)
value = positivePrism.GetOption(-5)   // None[int]

func PrismId

func PrismId[S any]() Prism[S, S]

PrismId returns an identity prism that focuses on the entire value. GetOption always returns Some(s), and ReverseGet is the identity function.

This is useful as a starting point for prism composition or when you need a prism that doesn't actually transform the value.

Example:

idPrism := PrismId[int]()
value := idPrism.GetOption(42)    // Some(42)
result := idPrism.ReverseGet(42)  // 42

func PrismSome

func PrismSome[S, A any](soa Prism[S, Option[A]]) Prism[S, A]

PrismSome creates a prism that focuses on the PrismSome variant of an Option within a structure. It composes the provided prism (which focuses on an Option[A]) with a prism that extracts the value from PrismSome.

Type Parameters:

  • S: The source type
  • A: The value type within the Option

Parameters:

  • soa: A prism that focuses on an Option[A] within S

Returns:

  • A prism that focuses on the A value within PrismSome

Example:

type Config struct { Timeout Option[int] }
configPrism := MakePrism(...)  // Prism[Config, Option[int]]
timeoutPrism := PrismSome(configPrism)  // Prism[Config, int]
value := timeoutPrism.GetOption(Config{Timeout: PrismSome(30)})  // PrismSome(30)

func (Prism[S, A]) Compose

func (p Prism[S, A]) Compose[B any](ab Prism[A, B]) Prism[S, B]

Compose returns a new prism that focuses deeper into a sum type by chaining this prism (S → A) with an inner prism (A → B), producing a composed prism (S → B).

This is the method-receiver form of the package-level OptionalComposeOptional function, available only on Go 1.27 and later because Go did not support type parameters on methods before that version. On earlier toolchains, use the equivalent free function instead:

// method form (go1.27+)
composed := outerPrism.Compose(innerPrism)

// free-function form (all versions)
composed := prism.Compose[S](innerPrism)(outerPrism)

GetOption of the composed prism chains the two GetOption functions: it first applies the outer prism to obtain an Option[A], then chains the inner prism through that option via O.Chain, returning None whenever either prism fails to match.

ReverseGet of the composed prism pipes the value back through both ReverseGet functions in order: inner first, then outer.

The composed prism satisfies both prism laws whenever both constituent prisms individually satisfy them.

Type Parameters:

  • B: the focus type of the inner prism and of the resulting prism

Parameters:

  • ab: the inner prism from A to B

Returns:

  • Prism[S, B]: a new prism from S directly to B

See Also:

  • Compose: the equivalent package-level function

func (Prism) Format

func (l Prism) Format(f fmt.State, c rune)

Format implements fmt.Formatter.

Supports all standard format verbs:

  • %s, %v, %+v, %q, and all other verbs: uses the String() representation (the prism name)

The exact output format is not a stable contract and may change across versions.

func (Prism) LogValue

func (l Prism) LogValue() slog.Value

LogValue implements slog.LogValuer.

Returns a slog.Value that represents the prism for structured logging. The prism name is logged as a string value. The exact structure of the returned slog.Value is not a stable contract and may change across versions.

func (Prism) String

func (l Prism) String() string

String returns the name of the prism for debugging and display purposes. The exact format is not a stable contract and may change across versions.

type PrismKleisli

type PrismKleisli[S, A, B any] = func(A) Prism[S, B]

Kleisli represents a function that takes a value of type A and returns a Prism[S, B]. This is commonly used for composing prisms in a monadic style.

Type Parameters:

  • S: The source type of the resulting prism
  • A: The input type to the function
  • B: The focus type of the resulting prism

type PrismOperator

type PrismOperator[S, A, B any] = func(Prism[S, A]) Prism[S, B]

Operator represents a function that transforms one prism into another. It takes a Prism[S, A] and returns a Prism[S, B], allowing for prism transformations.

Type Parameters:

  • S: The source type (remains constant)
  • A: The original focus type
  • B: The new focus type

func PrismComposePrism

func PrismComposePrism[S, A, B any](ab Prism[A, B]) PrismOperator[S, A, B]

Compose composes two prisms to create a prism that focuses deeper into a structure. The resulting prism first applies the outer prism (S → A), then the inner prism (A → B).

Type Parameters:

  • S: The outermost source type
  • A: The intermediate type
  • B: The innermost focus type

Parameters:

  • ab: The inner prism (A → B)

Returns:

  • A function that takes the outer prism (S → A) and returns the composed prism (S → B)

Example:

outerPrism := MakePrism(...)  // Prism[Outer, Inner]
innerPrism := MakePrism(...)  // Prism[Inner, Value]
composed := Compose[Outer](innerPrism)(outerPrism)  // Prism[Outer, Value]

func PrismIMap

func PrismIMap[S any, AB ~func(A) B, BA ~func(B) A, A, B any](ab AB, ba BA) PrismOperator[S, A, B]

PrismIMap bidirectionally maps the focus type of a prism. It transforms a Prism[S, A] into a Prism[S, B] using two functions: one to map A → B and another to map B → A.

Type Parameters:

  • S: The source type
  • A: The original focus type
  • B: The new focus type
  • AB: Function type A → B
  • BA: Function type B → A

Parameters:

  • ab: Function to map from A to B
  • ba: Function to map from B to A

Returns:

  • A function that transforms Prism[S, A] to Prism[S, B]

Example:

intPrism := MakePrism(...)  // Prism[Result, int]
stringPrism := PrismIMap[Result](
    strconv.Itoa,
    func(s string) int { n, _ := strconv.Atoi(s); return n },
)(intPrism)  // Prism[Result, string]

Jump to

Keyboard shortcuts

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