itereither

package
v2.3.2 Latest Latest
Warning

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

Go to latest
Published: May 12, 2026 License: Apache-2.0 Imports: 27 Imported by: 0

Documentation

Overview

Package itereither provides the SeqEither type, which represents an iterator that yields Either values, combining iteration with error handling.

SeqEither[E, A] is defined as iter.Seq[Either[E, A]], representing a sequence of values that can each be either an error of type E or a success value of type A.

Fantasy Land Specification

This package implements a monad transformer combining iteration with Either for error handling. It follows the Fantasy Land specification for functional programming patterns.

Implemented algebras:

  • Functor: Map operations over successful values
  • Bifunctor: Map operations over both error and success values
  • Apply: Apply wrapped functions to wrapped values
  • Applicative: Lift pure values into the context
  • Chain: Sequence dependent computations
  • Monad: Full monadic operations
  • Alt: Alternative computations for error recovery

Core Concepts

SeqEither combines two powerful abstractions:

  • Iteration: Processing sequences of values lazily
  • Either: Representing computations that can fail with typed errors

This allows for elegant error handling in iterator pipelines, where each element can independently succeed or fail, and operations can be chained while preserving error information.

Common Use Cases

  • Processing streams of data where individual items may fail
  • Parsing sequences where each element requires validation
  • Transforming collections with operations that can error
  • Building pipelines with graceful error propagation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BiMap

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

BiMap returns a function that maps a pair of functions over the two type arguments of the bifunctor

func ChainLeft

func ChainLeft[EA, EB, A any](f Kleisli[EB, EA, A]) func(SeqEither[EA, A]) SeqEither[EB, A]

ChainLeft is the curried version of MonadChainLeft. It returns a function that chains a computation on the left (error) side of a SeqEither.

Note: ChainLeft is identical to OrElse - both provide the same functionality for error recovery.

This is particularly useful in functional composition pipelines where you want to handle errors by performing another computation that may also fail.

Parameters:

  • f: A function that takes an error of type EA and returns a SeqEither with error type EB

Returns:

  • A function that transforms a SeqEither with error type EA to one with error type EB

Example:

// Create a reusable error handler
recoverFromNetworkError := ChainLeft(func(err string) SeqEither[string, int] {
    if strings.Contains(err, "network") {
        return Right[string](0) // return default value
    }
    return Left[int](err) // propagate other errors
})

result := F.Pipe1(
    Left[int]("network timeout"),
    recoverFromNetworkError,
)

func ChainOptionK

func ChainOptionK[A, B, E any](onNone func() E) func(O.Kleisli[A, B]) Operator[E, A, B]

func Fold

func Fold[E, A, B any](onLeft iter.Kleisli[E, B], onRight iter.Kleisli[A, B]) func(SeqEither[E, A]) Seq[B]

Fold converts an SeqEither into an Seq by providing handlers for both the error and success cases

func Functor

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

Functor implements the monadic operations for SeqEither

func GetOrElse

func GetOrElse[E, A any](onLeft iter.Kleisli[E, A]) func(SeqEither[E, A]) Seq[A]

GetOrElse extracts the value from a successful SeqEither or computes a default value from the error

func GetOrElseOf

func GetOrElseOf[E, A any](onLeft func(E) A) func(SeqEither[E, A]) Seq[A]

GetOrElseOf extracts the value from a successful SeqEither or computes a default value from the error

func MapLeft

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

MapLeft returns a function that applies a transformation to the error value of a failed SeqEither

func Monad

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

Monad implements the monadic operations for SeqEither

func Pointed

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

Pointed implements the pointed operations for SeqEither

func Reduce

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

Reduce returns a function that reduces a SeqEither to a single Either value. This is the curried version of MonadReduce.

The return type is IOEither because a SeqEither represents a dynamic lazy sequence of Either values. Reducing it requires consuming the iterator, so the final Either must also remain deferred as a lazy effect. IOEither is the single-value counterpart to SeqEither: both are lazy, and both represent work that is only performed when evaluated.

Type Parameters:

  • E: The error type
  • A: The element type in the sequence
  • B: The accumulator and result type

Parameters:

  • f: The reducer function that combines the accumulator with each element
  • initial: The initial accumulator value

Returns:

  • A function that takes a SeqEither and returns IOEither[E, B]

Example:

sum := Reduce(func(acc, x int) int { return acc + x }, 0)
seq := iter.From(E.Right[string](1), E.Right[string](2), E.Right[string](3))
resultIO := sum(seq)
result := resultIO()
// returns: E.Right[string](6)

func TraverseParTuple1

func TraverseParTuple1[E error, F1 ~func(A1) SeqEither[E, T1], T1, A1 any](f1 F1) func(tuple.Tuple1[A1]) SeqEither[E, tuple.Tuple1[T1]]

TraverseParTuple1 converts a [tuple.Tuple1[A1]] into a [SeqEither[E, tuple.Tuple1[T1]]]

func TraverseSeqTuple1

func TraverseSeqTuple1[E error, F1 ~func(A1) SeqEither[E, T1], T1, A1 any](f1 F1) func(tuple.Tuple1[A1]) SeqEither[E, tuple.Tuple1[T1]]

TraverseSeqTuple1 converts a [tuple.Tuple1[A1]] into a [SeqEither[E, tuple.Tuple1[T1]]]

func TraverseTuple1

func TraverseTuple1[E error, F1 ~func(A1) SeqEither[E, T1], T1, A1 any](f1 F1) func(tuple.Tuple1[A1]) SeqEither[E, tuple.Tuple1[T1]]

TraverseTuple1 converts a [tuple.Tuple1[A1]] into a [SeqEither[E, tuple.Tuple1[T1]]]

func TraverseTuple2

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

TraverseTuple2 converts a [tuple.Tuple2[A1, A2]] into a [SeqEither[E, tuple.Tuple2[T1, T2]]]

func TraverseTuple3

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

TraverseTuple3 converts a [tuple.Tuple3[A1, A2, A3]] into a [SeqEither[E, tuple.Tuple3[T1, T2, T3]]]

func TraverseTuple4

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

TraverseTuple4 converts a [tuple.Tuple4[A1, A2, A3, A4]] into a [SeqEither[E, tuple.Tuple4[T1, T2, T3, T4]]]

func TraverseTuple5

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

TraverseTuple5 converts a [tuple.Tuple5[A1, A2, A3, A4, A5]] into a [SeqEither[E, tuple.Tuple5[T1, T2, T3, T4, T5]]]

func TraverseTuple6

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

TraverseTuple6 converts a [tuple.Tuple6[A1, A2, A3, A4, A5, A6]] into a [SeqEither[E, tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]

func TraverseTuple7

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

TraverseTuple7 converts a [tuple.Tuple7[A1, A2, A3, A4, A5, A6, A7]] into a [SeqEither[E, tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]

func TraverseTuple8

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

TraverseTuple8 converts a [tuple.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]] into a [SeqEither[E, tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]

func TraverseTuple9

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

TraverseTuple9 converts a [tuple.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]] into a [SeqEither[E, tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]

func TraverseTuple10

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

TraverseTuple10 converts a [tuple.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]] into a [SeqEither[E, tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]

Types

type Either

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

Either represents a value that can be one of two types: Left (error) or Right (success). It is used for computations that may fail, providing a type-safe alternative to error handling with multiple return values.

Type Parameters:

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

type IO added in v2.3.0

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

IO represents a computation that performs side effects and returns a value of type T. IO computations are lazy - they don't execute until explicitly called. This allows for composing side-effecting operations in a pure, functional way.

Type Parameters:

  • T: The type of value produced by the IO computation

Example:

getCurrentTime := func() time.Time { return time.Now() }
// getCurrentTime is an IO[time.Time]

type IOEither added in v2.3.0

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

IOEither represents an IO computation that can either fail with an error of type E or succeed with a value of type T. It combines the side-effect handling of IO with the error handling of Either.

This is useful for operations that perform I/O and may fail, providing a type-safe alternative to returning (T, error) tuples.

Type Parameters:

  • E: The error type (Left)
  • T: The success type (Right)

Example:

readFile := func() either.Either[error, string] {
    data, err := os.ReadFile("config.txt")
    if err != nil {
        return either.Left[string](err)
    }
    return either.Right[error](string(data))
}
// readFile is an IOEither[error, string]

func Collect added in v2.3.0

func Collect[E, T any](fa SeqEither[E, T]) IOEither[E, []T]

Collect materializes a SeqEither into an Either containing a slice. It consumes all elements from the sequence, collecting Right values into a slice. If any Left (error) is encountered during iteration, collection stops immediately and returns that Left value.

The return type is IOEither because collecting a SeqEither is a reduction over a dynamic lazy source. The final Either is not available until iteration has happened, so it must stay deferred. IOEither is the single-value counterpart to SeqEither: both are lazy, and both represent work that is only performed when evaluated.

This function eagerly evaluates the entire sequence and accumulates all successful values into a slice in memory. It short-circuits on the first error.

Type Parameters:

  • E: The error type
  • T: The type of elements in the sequence

Parameters:

  • fa: The SeqEither to collect into a slice

Returns:

  • IOEither[E, []T]: A deferred computation that yields the first error encountered or a slice of all values

Marble Diagram:

Input:  --R(1)--R(2)--R(3)--R(4)--R(5)--|
Output: IO(Right([1, 2, 3, 4, 5]))

Input:  --R(1)--R(2)--L(e)--R(4)--R(5)--|
Output: IO(Left(e))

Example - Success case:

seq := iter.From(
    either.Right[string](1),
    either.Right[string](2),
    either.Right[string](3),
)
resultIO := Collect(seq)
result := resultIO()
// result = either.Right[string]([]int{1, 2, 3})

Example - Error case:

seq := iter.From(
    either.Right[string](1),
    either.Left[int]("error"),
    either.Right[string](3),
)
resultIO := Collect(seq)
result := resultIO()
// result = either.Left[[]int]("error")

Example - Empty sequence:

seq := iter.Empty[either.Either[string, int]]()
resultIO := Collect(seq)
result := resultIO()
// result = either.Right[string]([]int{})

See Also:

  • MonadReduce: Reduces a SeqEither to a single value
  • Fold: Converts SeqEither to Seq by handling both cases
  • GetOrElse: Extracts value or provides default

func MonadReduce

func MonadReduce[E, A, B any](fa SeqEither[E, A], f func(B, A) B, initial B) IOEither[E, B]

MonadReduce reduces a SeqEither to a single Either value by applying a function to each Right element and an accumulator, starting with an initial value. If any Left is encountered, reduction stops immediately and returns that Left value.

Type Parameters:

  • E: The error type
  • A: The element type in the sequence
  • B: The accumulator and result type

Parameters:

  • fa: The SeqEither to reduce
  • f: The reducer function that combines the accumulator with each element
  • initial: The initial accumulator value

Returns:

  • Either[E, B]: Left with the first error encountered, or Right with the final accumulated value

Marble Diagram:

Input:  --R(1)--R(2)--R(3)--R(4)--R(5)--|
Reduce((acc, x) => acc + x, 0)
Output: Right(15)

Input:  --R(1)--R(2)--L(e)--R(4)--R(5)--|
Reduce((acc, x) => acc + x, 0)
Output: Left(e)

Example:

seq := iter.From(E.Right[string](1), E.Right[string](2), E.Right[string](3))
sum := MonadReduce(seq, func(acc, x int) int { return acc + x }, 0)
// returns: E.Right[string](6)

seqWithError := iter.From(E.Right[string](1), E.Left[int]("error"), E.Right[string](3))
result := MonadReduce(seqWithError, func(acc, x int) int { return acc + x }, 0)
// returns: E.Left[int]("error")

type Kleisli

type Kleisli[E, A, B any] = R.Reader[A, SeqEither[E, B]]

Kleisli represents a function that takes a value and returns a SeqEither. This is the monadic bind operation for SeqEither, enabling composition of computations that may produce sequences of results or errors.

Type Parameters:

  • E: The error type
  • A: The input type
  • B: The element type of the output sequence

Example:

validate := func(x int) SeqEither[string, int] {
    if x > 0 {
        return Right[string](x)
    }
    return Left[int]("must be positive")
}
// validate is a Kleisli[string, int, int]

func FromOption

func FromOption[A, E any](onNone func() E) Kleisli[E, O.Option[A], A]

func OrElse

func OrElse[E1, E2, A any](onLeft Kleisli[E2, E1, A]) Kleisli[E2, SeqEither[E1, A], A]

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

Note: OrElse is identical to ChainLeft - both provide the same functionality for error recovery.

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

Example:

// Recover from specific errors with fallback IO operations
recover := ioeither.OrElse(func(err error) ioeither.SeqEither[error, int] {
    if err.Error() == "not found" {
        return ioeither.Right[error](0) // default value
    }
    return ioeither.Left[int](err) // propagate other errors
})
result := recover(ioeither.Left[int](errors.New("not found"))) // Right(0)
result := recover(ioeither.Right[error](42)) // Right(42) - unchanged

func TraverseArray

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

TraverseArray transforms an array

func TraverseArrayWithIndex

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

TraverseArrayWithIndex transforms an array

func TraverseRecord

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

TraverseRecord transforms a record

func TraverseRecordWithIndex

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

TraverseRecordWithIndex transforms a record

func WithResource

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

WithResource constructs a function that safely manages a resource with automatic cleanup. It creates a resource, operates on it, and ensures the resource is released even if an error occurs.

type Lazy added in v2.3.0

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

Lazy represents a deferred computation that produces a value of type T. The computation is not executed until the Lazy value is called. This is an alias for IO and provides semantic clarity when working with lazy evaluations that don't necessarily involve side effects.

Type Parameters:

  • T: The type of value produced by the lazy computation

Example:

expensiveCalc := func() int {
    // Expensive computation
    return 42
}
// expensiveCalc is a Lazy[int]

type Monoid

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

func ApplicativeMonoid

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

ApplicativeMonoid returns a Monoid that concatenates SeqEither instances via their applicative

type Operator

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

Operator represents a transformation from one SeqEither to another. It takes a SeqEither[E, A] and returns a SeqEither[E, B], allowing for composition of sequence transformations in a functional pipeline.

Type Parameters:

  • E: The error type (preserved across the transformation)
  • A: The element type of the input sequence
  • B: The element type of the output sequence

Example:

double := Map[string](func(x int) int { return x * 2 })
// double is an Operator[string, int, int]

func Alt

func Alt[E, A any](second lazy.Lazy[SeqEither[E, A]]) Operator[E, A, A]

Alt returns a function that provides an alternative SeqEither computation if the first one fails

func Ap

func Ap[B, E, A any](ma SeqEither[E, A]) Operator[E, func(A) B, B]

Ap applies a function wrapped in an SeqEither to a value wrapped in an SeqEither. This is an alias of [ApPar] which applies the function and value in parallel.

func ApFirst

func ApFirst[A, E, B any](second SeqEither[E, B]) Operator[E, A, A]

ApFirst combines two effectful actions, keeping only the result of the first.

Marble diagram:

First:  ---R(1)---R(2)---|
Second: ---R(10)---R(20)---|
Output: ---R(1)---R(2)---|

If either sequence contains a Left, the error is propagated.

func ApS

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

ApS attaches a value to a context S1 to produce a context S2 by considering the context and the value concurrently (using Applicative rather than Monad). This allows independent computations to be combined without one depending on the result of the other.

Unlike Bind, which sequences operations, ApS can be used when operations are independent and can conceptually run in parallel.

Example:

type State struct {
    User  User
    Posts []Post
}

// These operations are independent and can be combined with ApS
getUser := ioeither.Right[error](User{ID: 1, Name: "Alice"})
getPosts := ioeither.Right[error]([]Post{{ID: 1, Title: "Hello"}})

result := F.Pipe2(
    ioeither.Do[error](State{}),
    ioeither.ApS(
        func(user User) func(State) State {
            return func(s State) State { s.User = user; return s }
        },
        getUser,
    ),
    ioeither.ApS(
        func(posts []Post) func(State) State {
            return func(s State) State { s.Posts = posts; return s }
        },
        getPosts,
    ),
)

func ApSL

func ApSL[E, S, T any](
	lens L.Lens[S, T],
	fa SeqEither[E, T],
) Operator[E, S, S]

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

The lens parameter provides both the getter and setter for a field within the structure S. This eliminates the need to manually write setter functions.

Example:

type Config struct {
    Host string
    Port int
}

portLens := lens.MakeLens(
    func(c Config) int { return c.Port },
    func(c Config, p int) Config { c.Port = p; return c },
)

result := F.Pipe2(
    ioeither.Of[error](Config{Host: "localhost"}),
    ioeither.ApSL(portLens, ioeither.Of[error](8080)),
)

func ApSecond

func ApSecond[A, E, B any](second SeqEither[E, B]) Operator[E, A, B]

ApSecond combines two effectful actions, keeping only the result of the second.

Marble diagram:

First:  ---R(1)---R(2)---|
Second: ---R(10)---R(20)---|
Output: ---R(10)---R(20)---|

If either sequence contains a Left, the error is propagated.

func Bind

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

Bind attaches the result of a computation to a context S1 to produce a context S2. This enables sequential composition where each step can depend on the results of previous steps.

The setter function takes the result of the computation and returns a function that updates the context from S1 to S2.

Example:

type State struct {
    User  User
    Posts []Post
}

result := F.Pipe2(
    ioeither.Do[error](State{}),
    ioeither.Bind(
        func(user User) func(State) State {
            return func(s State) State { s.User = user; return s }
        },
        func(s State) ioeither.SeqEither[error, User] {
            return ioeither.TryCatch(func() (User, error) {
                return fetchUser()
            })
        },
    ),
    ioeither.Bind(
        func(posts []Post) func(State) State {
            return func(s State) State { s.Posts = posts; return s }
        },
        func(s State) ioeither.SeqEither[error, []Post] {
            // This can access s.User from the previous step
            return ioeither.TryCatch(func() ([]Post, error) {
                return fetchPostsForUser(s.User.ID)
            })
        },
    ),
)

func BindL

func BindL[E, S, T any](
	lens L.Lens[S, T],
	f Kleisli[E, T, T],
) Operator[E, S, S]

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

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

Example:

type Counter struct {
    Value int
}

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

increment := func(v int) ioeither.SeqEither[error, int] {
    return ioeither.TryCatch(func() (int, error) {
        if v >= 100 {
            return 0, errors.New("overflow")
        }
        return v + 1, nil
    })
}

result := F.Pipe1(
    ioeither.Of[error](Counter{Value: 42}),
    ioeither.BindL(valueLens, increment),
)

func BindTo

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

BindTo initializes a new state S1 from a value T

func Chain

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

Chain returns a function that sequences two SeqEither computations

func ChainEitherK

func ChainEitherK[E, A, B any](f either.Kleisli[E, A, B]) Operator[E, A, B]

func ChainFirst

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

ChainFirst returns a function that executes a side-effecting SeqEither computation but returns the original value

func ChainFirstEitherK

func ChainFirstEitherK[A, E, B any](f either.Kleisli[E, A, B]) Operator[E, A, A]

ChainFirstEitherK returns a function that executes a side-effecting Either computation but returns the original value

func ChainFirstLeft

func ChainFirstLeft[A, EA, EB, B any](f Kleisli[EB, EA, B]) Operator[EA, A, A]

ChainFirstLeft is the curried version of MonadChainFirstLeft. It returns a function that chains a computation on the left (error) side while always preserving the original error.

This is particularly useful for adding error handling side effects (like logging, metrics, or notifications) in a functional pipeline. The original error is always returned regardless of what f returns (Left or Right), ensuring the error path is preserved.

Parameters:

  • f: A function that takes an error of type EA and returns a SeqEither (typically for side effects)

Returns:

  • An Operator that performs the side effect but always returns the original error if input was Left

Example:

// Create a reusable error logger
logError := ChainFirstLeft(func(err string) SeqEither[any, int] {
    return FromIO[any](func() int {
        log.Printf("Error: %s", err)
        return 0
    })
})

result := F.Pipe1(
    Left[int]("validation failed"),
    logError, // logs the error
)
// result is always Left("validation failed"), even though f returns Right

func ChainSeqK

func ChainSeqK[E, A, B any](f iter.Kleisli[A, B]) Operator[E, A, B]

func ChainTo

func ChainTo[A, E, B any](fb SeqEither[E, B]) Operator[E, A, B]

ChainTo returns a function that sequences two SeqEither computations, discarding the result of the first

func ChainToSeq

func ChainToSeq[E, A, B any](fb Seq[B]) Operator[E, A, B]

ChainToSeq returns a function that sequences an SeqEither with an Seq, discarding the result of the first

func Filter added in v2.3.1

func Filter[E, A any](pred func(A) bool) Operator[E, A, A]

Filter returns a function that filters SeqEither elements based on a predicate. This is the curried version of MonadFilter, useful for creating reusable filter operations.

The returned function keeps only Right values that satisfy the predicate, while passing all Left values through unchanged. Right values that fail the predicate are removed from the sequence.

Type Parameters:

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

Parameters:

  • pred: A predicate function that tests Right values

Returns:

  • An Operator that filters SeqEither sequences based on the predicate

Example:

// Create a reusable filter for even numbers
evens := itereither.Filter[string](func(x int) bool { return x%2 == 0 })

seq1 := iter.From(E.Right[string](1), E.Right[string](2), E.Right[string](3))
result1 := evens(seq1)
// yields: Right(2)

seq2 := iter.From(E.Right[string](4), E.Left[int]("error"), E.Right[string](5))
result2 := evens(seq2)
// yields: Right(4), Left("error")

See Also:

MonadFilter is the non-curried version. FilterOrElse converts failing values to Left instead of removing them.

func FilterOrElse

func FilterOrElse[E, A any](pred Predicate[A], onFalse func(A) E) Operator[E, A, A]

FilterOrElse filters a SeqEither value based on a predicate. If the predicate returns true for the Right value, it passes through unchanged. If the predicate returns false, it transforms the Right value into a Left using onFalse. Left values are passed through unchanged.

This is useful for adding validation or constraints to successful computations, converting values that don't meet certain criteria into errors.

Marble diagram:

Input:  ---R(5)---R(-3)---L(e)---R(10)---|
pred(x) = x > 0
onFalse(x) = "negative: " + x
Output: ---R(5)---L("negative: -3")---L(e)---R(10)---|

Where R(x) represents Right(x) and L(e) represents Left(e). Values that fail the predicate are converted to Left.

Parameters:

  • pred: A predicate function that tests the Right value
  • onFalse: A function that converts the failing value into an error of type E

Returns:

  • An Operator that filters SeqEither values based on the predicate

Example:

// Validate that a number is positive
isPositive := N.MoreThan(0)
onNegative := S.Format[int]("%d is not positive")

validatePositive := itereither.FilterOrElse(isPositive, onNegative)

result1 := validatePositive(itereither.Right[string](42))  // Right(42)
result2 := validatePositive(itereither.Right[string](-5))  // Left("-5 is not positive")
result3 := validatePositive(itereither.Left[int]("error")) // Left("error")

func Flap

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

Flap returns a function that applies a value to a function wrapped in an SeqEither

func Let

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

Let attaches the result of a computation to a context S1 to produce a context S2

func LetL

func LetL[E, S, T any](
	lens L.Lens[S, T],
	f func(T) T,
) Operator[E, S, S]

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

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

Example:

type Counter struct {
    Value int
}

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

double := func(v int) int { return v * 2 }

result := F.Pipe1(
    ioeither.Of[error](Counter{Value: 21}),
    ioeither.LetL(valueLens, double),
)

func LetTo

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

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

func LetToL

func LetToL[E, S, T any](
	lens L.Lens[S, T],
	b T,
) Operator[E, S, S]

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

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

Example:

type Config struct {
    Debug   bool
    Timeout int
}

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

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

func Map

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

Map returns a function that applies a transformation to the value inside a successful SeqEither.

Marble diagram:

Input:  ---R(1)---R(2)---L(e)---R(3)---|
f(x) = x * 2
Output: ---R(2)---R(4)---L(e)---R(6)---|

Where R(x) represents Right(x) and L(e) represents Left(e).

func MapTo

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

MapTo returns a function that replaces the value inside a successful SeqEither with a constant value

func MergeMap

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

MergeMap returns a function that sequences two SeqEither computations

func MergeMapFirstEitherK

func MergeMapFirstEitherK[A, E, B any](f either.Kleisli[E, A, B]) Operator[E, A, A]

MergeMapFirstEitherK returns a function that executes a side-effecting Either computation but returns the original value

func MergeMapSeqK

func MergeMapSeqK[E, A, B any](f iter.Kleisli[A, B]) Operator[E, A, B]

func Tap

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

Tap is an alias for ChainFirst, executing a side effect while preserving the original value

func TapEitherK

func TapEitherK[A, E, B any](f either.Kleisli[E, A, B]) Operator[E, A, A]

TapEitherK is an alias for ChainFirstEitherK, executing an Either side effect while preserving the original value

func TapLeft

func TapLeft[A, EA, EB, B any](f Kleisli[EB, EA, B]) Operator[EA, A, A]

type Predicate

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

Predicate represents a function that tests a value of type A and returns a boolean. It's commonly used for filtering and conditional operations.

type Semigroup

type Semigroup[E, A any] = semigroup.Semigroup[SeqEither[E, A]]

func AltSemigroup

func AltSemigroup[E, A any]() Semigroup[E, A]

AltSemigroup is a Semigroup that tries the first item and then the second one using an alternative

type Seq

type Seq[A any] = iter.Seq[A]

Seq is a single-value iterator sequence from Go 1.23+. It represents a lazy sequence of values that can be iterated using range.

Type Parameters:

  • A: The type of elements in the sequence

func MonadFold

func MonadFold[E, A, B any](ma SeqEither[E, A], onLeft iter.Kleisli[E, B], onRight iter.Kleisli[A, B]) Seq[B]

MonadFold eliminates an SeqEither by providing handlers for both error and success cases, returning an Seq

type SeqEither

type SeqEither[E, A any] = Seq[Either[E, A]]

SeqEither represents a lazy sequence of Either values. Each element in the sequence can be either a Left (error) or Right (success). This combines the lazy evaluation of sequences with the error handling of Either.

Type Parameters:

  • E: The error type
  • A: The success type

Example:

seq := iter.From(
    either.Right[string](1),
    either.Right[string](2),
    either.Left[int]("error"),
)
// seq is a SeqEither[string, int]

func Bracket

func Bracket[E, A, B, ANY any](
	acquire SeqEither[E, A],
	use Kleisli[E, A, B],
	release func(A, Either[E, B]) SeqEither[E, ANY],
) SeqEither[E, B]

Bracket makes sure that a resource is cleaned up in the event of an error. The release action is called regardless of whether the body action returns an error or not.

Marble diagram (successful case):

Acquire: ---R(resource)---|
Use:     ---R(result1)---R(result2)---|
Release: (called with resource and Right(result2))
Output:  ---R(result1)---R(result2)---|

Marble diagram (error case):

Acquire: ---R(resource)---|
Use:     ---R(result1)---L(error)---|
Release: (called with resource and Left(error))
Output:  ---R(result1)---L(error)---|

The release function is always called to clean up the resource, even when an error occurs during use.

func Do

func Do[E, S any](
	empty S,
) SeqEither[E, S]

Do creates an empty context of type S to be used with the Bind operation. This is the starting point for do-notation style composition.

Example:

type State struct {
    User  User
    Posts []Post
}
result := ioeither.Do[error](State{})

func Flatten

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

Flatten removes one level of nesting from a nested SeqEither

func FromEither

func FromEither[E, A any](e Either[E, A]) SeqEither[E, A]

FromEither lifts an Either value into the SeqEither context

func FromIO added in v2.3.0

func FromIO[E, A any](mr IO[A]) SeqEither[E, A]

FromIO converts an IO computation into a single-element SeqEither containing a Right value. The IO computation is executed when the sequence is consumed, and its result is wrapped in a Right, creating a successful SeqEither.

This function bridges IO computations with SeqEither, allowing side effects that always succeed to be integrated into error-handling pipelines.

Type Parameters:

  • E: The error type (not used, but required for type consistency)
  • A: The type of value produced by the IO computation

Parameters:

  • mr: An IO computation that produces a value of type A

Returns:

  • SeqEither[E, A]: A sequence containing a single Right value with the IO result

Example:

getCurrentTime := func() time.Time { return time.Now() }
seq := FromIO[error](getCurrentTime)
// seq yields: Right(current time) when consumed

See Also:

  • FromLazy: Converts a Lazy computation to SeqEither
  • FromIOEither: Converts an IOEither to SeqEither
  • Right: Creates a SeqEither from a pure value

func FromIOEither added in v2.3.0

func FromIOEither[E, A any](mr IOEither[E, A]) SeqEither[E, A]

FromIOEither converts an IOEither computation into a single-element SeqEither. The IOEither computation is executed when the sequence is consumed, and its result (either Left or Right) becomes the single element of the sequence.

This function bridges IOEither computations with SeqEither, allowing deferred I/O operations that may fail to be integrated into sequence-based error-handling pipelines.

Type Parameters:

  • E: The error type
  • A: The success type

Parameters:

  • mr: An IOEither computation that produces Either[E, A]

Returns:

  • SeqEither[E, A]: A sequence containing the single Either value from the deferred IOEither

Example:

readConfig := func() either.Either[error, Config] {
    data, err := os.ReadFile("config.json")
    if err != nil {
        return either.Left[Config](err)
    }
    return either.Right[error](parseConfig(data))
}
seq := FromIOEither(readConfig)
// The IOEither is only executed when the sequence is iterated.

See Also:

  • FromIO: Converts an IO computation to SeqEither (always Right)
  • FromLazy: Converts a Lazy computation to SeqEither (always Right)
  • FromEither: Converts a pure Either to SeqEither

func FromLazy added in v2.3.0

func FromLazy[E, A any](mr Lazy[A]) SeqEither[E, A]

FromLazy converts a Lazy computation into a single-element SeqEither containing a Right value. The Lazy computation is executed when the sequence is consumed, and its result is wrapped in a Right, creating a successful SeqEither.

This is a convenience function that provides semantic clarity when working with lazy computations. It delegates to FromIO since Lazy is an alias for IO.

Type Parameters:

  • E: The error type (not used, but required for type consistency)
  • A: The type of value produced by the Lazy computation

Parameters:

  • mr: A Lazy computation that produces a value of type A

Returns:

  • SeqEither[E, A]: A sequence containing a single Right value with the Lazy result

Example:

expensiveCalc := func() int {
    // Expensive computation
    return 42
}
seq := FromLazy[error](expensiveCalc)
// Computation only runs when sequence is consumed
// seq yields: Right(42)

See Also:

  • FromIO: Converts an IO computation to SeqEither
  • FromIOEither: Converts an IOEither to SeqEither
  • Right: Creates a SeqEither from a pure value

func FromSeq

func FromSeq[E, A any](mr Seq[A]) SeqEither[E, A]

FromSeq creates an SeqEither from an Seq instance, invoking Seq for each invocation of SeqEither

func Left

func Left[A, E any](l E) SeqEither[E, A]

Left constructs an SeqEither that represents a failure with an error value of type E

func LeftSeq

func LeftSeq[A, E any](ml Seq[E]) SeqEither[E, A]

LeftSeq constructs an SeqEither from an Seq that produces an error value

func MonadAlt

func MonadAlt[E, A any](first SeqEither[E, A], second lazy.Lazy[SeqEither[E, A]]) SeqEither[E, A]

MonadAlt provides an alternative SeqEither computation if the first one fails.

Marble diagram:

First:  ---L(e1)---L(e2)---|
Second: ---R(1)---R(2)---|
Output: ---R(1)---R(2)---L(e2)---|

When a Left is encountered, it's replaced with values from the second sequence. Right values from the first sequence pass through unchanged.

func MonadAp

func MonadAp[B, E, A any](mab SeqEither[E, func(A) B], ma SeqEither[E, A]) SeqEither[E, B]

MonadAp applies a function wrapped in an SeqEither to a value wrapped in an SeqEither

func MonadApFirst

func MonadApFirst[A, E, B any](first SeqEither[E, A], second SeqEither[E, B]) SeqEither[E, A]

MonadApFirst combines two effectful actions, keeping only the result of the first.

Marble diagram:

First:  ---R(1)---R(2)---|
Second: ---R(10)---R(20)---|
Output: ---R(1)---R(2)---|

If either sequence contains a Left, the error is propagated:

First:  ---R(1)---L(e)---|
Second: ---R(10)---R(20)---|
Output: ---R(1)---L(e)---|

func MonadApSecond

func MonadApSecond[A, E, B any](first SeqEither[E, A], second SeqEither[E, B]) SeqEither[E, B]

MonadApSecond combines two effectful actions, keeping only the result of the second.

Marble diagram:

First:  ---R(1)---R(2)---|
Second: ---R(10)---R(20)---|
Output: ---R(10)---R(20)---|

If either sequence contains a Left, the error is propagated:

First:  ---R(1)---L(e)---|
Second: ---R(10)---R(20)---|
Output: ---R(10)---L(e)---|

func MonadBiMap

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

MonadBiMap applies one function to the error value and another to the success value of a SeqEither.

Marble diagram:

Input:  ---L(e1)---R(1)---L(e2)---R(2)---|
f(e) = len(e), g(x) = x * 2
Output: ---L(3)---R(2)---L(3)---R(4)---|

Both Left and Right values are transformed according to their respective functions.

func MonadChain

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

MonadChain sequences two SeqEither computations, where the second depends on the result of the first.

Marble diagram:

Input:  ---R(1)-------R(2)---L(e)---|
f(1) -> ---R(10)---R(11)---|
f(2) -> ---R(20)---R(21)---|
Output: ---R(10)---R(11)---R(20)---R(21)---L(e)---|

Each Right value is transformed into a sequence, which is then flattened. Left values pass through unchanged and stop further processing.

func MonadChainEitherK

func MonadChainEitherK[E, A, B any](ma SeqEither[E, A], f either.Kleisli[E, A, B]) SeqEither[E, B]

func MonadChainFirst

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

MonadChainFirst executes a side-effecting SeqEither computation but returns the original value

func MonadChainFirstEitherK

func MonadChainFirstEitherK[A, E, B any](ma SeqEither[E, A], f either.Kleisli[E, A, B]) SeqEither[E, A]

MonadChainFirstEitherK executes a side-effecting Either computation but returns the original SeqEither value

func MonadChainFirstLeft

func MonadChainFirstLeft[A, EA, EB, B any](ma SeqEither[EA, A], f Kleisli[EB, EA, B]) SeqEither[EA, A]

MonadChainFirstLeft chains a computation on the left (error) side but always returns the original error. If the input is a Left value, it applies the function f to the error and executes the resulting computation, but always returns the original Left error regardless of what f returns (Left or Right). If the input is a Right value, it passes through unchanged without calling f.

This is useful for side effects on errors (like logging or metrics) where you want to perform an action when an error occurs but always propagate the original error, ensuring the error path is preserved.

Parameters:

  • ma: The input SeqEither that may contain an error of type EA
  • f: A function that takes an error of type EA and returns a SeqEither (typically for side effects)

Returns:

  • A SeqEither with the original error preserved if input was Left, or the original Right value

Example:

// Log errors but always preserve the original error
result := MonadChainFirstLeft(
    Left[int]("database error"),
    func(err string) SeqEither[string, int] {
        return FromIO[string](func() int {
            log.Printf("Error occurred: %s", err)
            return 0
        })
    },
)
// result will always be Left("database error"), even though f returns Right

func MonadChainLeft

func MonadChainLeft[EA, EB, A any](fa SeqEither[EA, A], f Kleisli[EB, EA, A]) SeqEither[EB, A]

MonadChainLeft chains a computation on the left (error) side of a SeqEither. If the input is a Left value, it applies the function f to transform the error and potentially change the error type from EA to EB. If the input is a Right value, it passes through unchanged.

Note: MonadChainLeft is identical to OrElse - both provide the same functionality for error recovery.

This is useful for error recovery or error transformation scenarios where you want to handle errors by performing another computation that may also fail.

Parameters:

  • fa: The input SeqEither that may contain an error of type EA
  • f: A function that takes an error of type EA and returns a SeqEither with error type EB

Returns:

  • A SeqEither with the potentially transformed error type EB

Example:

// Recover from a specific error by trying an alternative computation
result := MonadChainLeft(
    Left[int]("network error"),
    func(err string) SeqEither[string, int] {
        if err == "network error" {
            return Right[string](42) // recover with default value
        }
        return Left[int]("unrecoverable: " + err)
    },
)

func MonadChainSeqK

func MonadChainSeqK[E, A, B any](ma SeqEither[E, A], f iter.Kleisli[A, B]) SeqEither[E, B]

func MonadChainTo

func MonadChainTo[A, E, B any](fa SeqEither[E, A], fb SeqEither[E, B]) SeqEither[E, B]

MonadChainTo sequences two SeqEither computations, discarding the result of the first

func MonadChainToSeq

func MonadChainToSeq[E, A, B any](fa SeqEither[E, A], fb Seq[B]) SeqEither[E, B]

MonadChainToSeq sequences an SeqEither with an Seq, discarding the result of the first

func MonadFilter added in v2.3.1

func MonadFilter[E, A any](as SeqEither[E, A], pred Predicate[A]) SeqEither[E, A]

MonadFilter filters a SeqEither sequence, keeping only Right values that satisfy the predicate. Left values are always passed through unchanged, regardless of the predicate.

This function processes each element in the sequence:

  • If the element is Left, it passes through unchanged
  • If the element is Right and satisfies the predicate, it passes through
  • If the element is Right but fails the predicate, it is filtered out

Unlike FilterOrElse, which converts failing Right values to Left, MonadFilter simply removes them from the sequence entirely.

Marble diagram:

Input:  --R(1)--R(2)--L(e)--R(3)--R(4)--R(5)-->
pred(x) = x % 2 == 0
Output: --------R(2)--L(e)--------R(4)-------->

Where R(x) represents Right(x) and L(e) represents Left(e). Odd numbers are filtered out, even numbers and errors pass through.

Type Parameters:

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

Parameters:

  • as: The input SeqEither sequence to filter
  • pred: A predicate function that tests Right values

Returns:

  • A SeqEither containing only Left values and Right values that satisfy the predicate

Example:

seq := iter.From(
    E.Right[string](1),
    E.Right[string](2),
    E.Left[int]("error"),
    E.Right[string](3),
    E.Right[string](4),
)
isEven := func(x int) bool { return x%2 == 0 }
result := itereither.MonadFilter(seq, isEven)
// yields: Right(2), Left("error"), Right(4)

See Also:

Filter is the curried version of MonadFilter. FilterOrElse converts failing values to Left instead of removing them.

func MonadFlap

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

MonadFlap applies a value to a function wrapped in an SeqEither

func MonadMap

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

MonadMap applies a function to the value inside a successful SeqEither, leaving errors unchanged.

Marble diagram:

Input:  ---R(1)---R(2)---L(e)---R(3)---|
f(x) = x * 2
Output: ---R(2)---R(4)---L(e)---R(6)---|

Where R(x) represents Right(x) and L(e) represents Left(e).

func MonadMapLeft

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

MonadMapLeft applies a function to the error value of a failed SeqEither, leaving successful values unchanged.

Marble diagram:

Input:  ---L(e1)---R(1)---L(e2)---R(2)---|
f(e) = "error: " + e
Output: ---L("error: e1")---R(1)---L("error: e2")---R(2)---|

Where R(x) represents Right(x) and L(e) represents Left(e).

func MonadMapTo

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

MonadMapTo replaces the value inside a successful SeqEither with a constant value

func MonadMergeMap

func MonadMergeMap[E, A, B any](fa SeqEither[E, A], f Kleisli[E, A, B]) SeqEither[E, B]

MonadMergeMap sequences two SeqEither computations, where the second depends on the result of the first. Unlike MonadChain, MergeMap interleaves results from concurrent sequences.

Marble diagram:

Input:  ---R(1)-------R(2)---|
f(1) -> ---R(10)------R(11)---|
f(2) -> ------R(20)------R(21)---|
Output: ---R(10)---R(20)---R(11)---R(21)---|

Results are interleaved as they become available, rather than waiting for each sequence to complete.

func MonadMergeMapFirstEitherK

func MonadMergeMapFirstEitherK[A, E, B any](ma SeqEither[E, A], f either.Kleisli[E, A, B]) SeqEither[E, A]

MonadMergeMapFirstEitherK executes a side-effecting Either computation but returns the original SeqEither value

func MonadMergeMapSeqK

func MonadMergeMapSeqK[E, A, B any](ma SeqEither[E, A], f iter.Kleisli[A, B]) SeqEither[E, B]

func MonadOf

func MonadOf[E, A any](r A) SeqEither[E, A]

MonadOf is an alias for Of, provided for consistency with monad naming conventions

func MonadTap

func MonadTap[E, A, B any](ma SeqEither[E, A], f Kleisli[E, A, B]) SeqEither[E, A]

MonadTap is an alias for MonadChainFirst, executing a side effect while preserving the original value

func MonadTapEitherK

func MonadTapEitherK[A, E, B any](ma SeqEither[E, A], f either.Kleisli[E, A, B]) SeqEither[E, A]

MonadTapEitherK is an alias for MonadChainFirstEitherK, executing an Either side effect while preserving the original value

func MonadTapLeft

func MonadTapLeft[A, EA, EB, B any](ma SeqEither[EA, A], f Kleisli[EB, EA, B]) SeqEither[EA, A]

func Of

func Of[E, A any](r A) SeqEither[E, A]

Of constructs an SeqEither that represents a successful computation with a value of type A. This is an alias for Right and is the canonical way to lift a pure value into the SeqEither context.

func Right[E, A any](r A) SeqEither[E, A]

Right constructs an SeqEither that represents a successful computation with a value of type A

func RightSeq

func RightSeq[E, A any](mr Seq[A]) SeqEither[E, A]

RightSeq constructs an SeqEither from an Seq that produces a success value

func SequenceArray

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

SequenceArray converts a homogeneous sequence of either into an either of sequence

func SequenceParT1

func SequenceParT1[E, T1 any](
	t1 SeqEither[E, T1],
) SeqEither[E, tuple.Tuple1[T1]]

SequenceParT1 converts 1 [SeqEither[E, T]] into a [SeqEither[E, tuple.Tuple1[T1]]]

func SequenceParTuple1

func SequenceParTuple1[E, T1 any](t tuple.Tuple1[SeqEither[E, T1]]) SeqEither[E, tuple.Tuple1[T1]]

SequenceParTuple1 converts a [tuple.Tuple1[SeqEither[E, T]]] into a [SeqEither[E, tuple.Tuple1[T1]]]

func SequenceRecord

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

SequenceRecord converts a homogeneous sequence of either into an either of sequence

func SequenceSeqT1

func SequenceSeqT1[E, T1 any](
	t1 SeqEither[E, T1],
) SeqEither[E, tuple.Tuple1[T1]]

SequenceSeqT1 converts 1 [SeqEither[E, T]] into a [SeqEither[E, tuple.Tuple1[T1]]]

func SequenceSeqTuple1

func SequenceSeqTuple1[E, T1 any](t tuple.Tuple1[SeqEither[E, T1]]) SeqEither[E, tuple.Tuple1[T1]]

SequenceSeqTuple1 converts a [tuple.Tuple1[SeqEither[E, T]]] into a [SeqEither[E, tuple.Tuple1[T1]]]

func SequenceT1

func SequenceT1[E, T1 any](
	t1 SeqEither[E, T1],
) SeqEither[E, tuple.Tuple1[T1]]

SequenceT1 converts 1 [SeqEither[E, T]] into a [SeqEither[E, tuple.Tuple1[T1]]]

func SequenceT2

func SequenceT2[E, T1, T2 any](
	t1 SeqEither[E, T1],
	t2 SeqEither[E, T2],
) SeqEither[E, tuple.Tuple2[T1, T2]]

SequenceT2 converts 2 [SeqEither[E, T]] into a [SeqEither[E, tuple.Tuple2[T1, T2]]]

func SequenceT3

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

SequenceT3 converts 3 [SeqEither[E, T]] into a [SeqEither[E, tuple.Tuple3[T1, T2, T3]]]

func SequenceT4

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

SequenceT4 converts 4 [SeqEither[E, T]] into a [SeqEither[E, tuple.Tuple4[T1, T2, T3, T4]]]

func SequenceT5

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

SequenceT5 converts 5 [SeqEither[E, T]] into a [SeqEither[E, tuple.Tuple5[T1, T2, T3, T4, T5]]]

func SequenceT6

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

SequenceT6 converts 6 [SeqEither[E, T]] into a [SeqEither[E, tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]

func SequenceT7

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

SequenceT7 converts 7 [SeqEither[E, T]] into a [SeqEither[E, tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]

func SequenceT8

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

SequenceT8 converts 8 [SeqEither[E, T]] into a [SeqEither[E, tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]

func SequenceT9

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

SequenceT9 converts 9 [SeqEither[E, T]] into a [SeqEither[E, tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]

func SequenceT10

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

SequenceT10 converts 10 [SeqEither[E, T]] into a [SeqEither[E, tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]

func SequenceTuple1

func SequenceTuple1[E, T1 any](t tuple.Tuple1[SeqEither[E, T1]]) SeqEither[E, tuple.Tuple1[T1]]

SequenceTuple1 converts a [tuple.Tuple1[SeqEither[E, T]]] into a [SeqEither[E, tuple.Tuple1[T1]]]

func SequenceTuple2

func SequenceTuple2[E, T1, T2 any](t tuple.Tuple2[SeqEither[E, T1], SeqEither[E, T2]]) SeqEither[E, tuple.Tuple2[T1, T2]]

SequenceTuple2 converts a [tuple.Tuple2[SeqEither[E, T]]] into a [SeqEither[E, tuple.Tuple2[T1, T2]]]

func SequenceTuple3

func SequenceTuple3[E, T1, T2, T3 any](t tuple.Tuple3[SeqEither[E, T1], SeqEither[E, T2], SeqEither[E, T3]]) SeqEither[E, tuple.Tuple3[T1, T2, T3]]

SequenceTuple3 converts a [tuple.Tuple3[SeqEither[E, T]]] into a [SeqEither[E, tuple.Tuple3[T1, T2, T3]]]

func SequenceTuple4

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

SequenceTuple4 converts a [tuple.Tuple4[SeqEither[E, T]]] into a [SeqEither[E, tuple.Tuple4[T1, T2, T3, T4]]]

func SequenceTuple5

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

SequenceTuple5 converts a [tuple.Tuple5[SeqEither[E, T]]] into a [SeqEither[E, tuple.Tuple5[T1, T2, T3, T4, T5]]]

func SequenceTuple6

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

SequenceTuple6 converts a [tuple.Tuple6[SeqEither[E, T]]] into a [SeqEither[E, tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]

func SequenceTuple7

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

SequenceTuple7 converts a [tuple.Tuple7[SeqEither[E, T]]] into a [SeqEither[E, tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]

func SequenceTuple8

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

SequenceTuple8 converts a [tuple.Tuple8[SeqEither[E, T]]] into a [SeqEither[E, tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]

func SequenceTuple9

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

SequenceTuple9 converts a [tuple.Tuple9[SeqEither[E, T]]] into a [SeqEither[E, tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]

func SequenceTuple10

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

SequenceTuple10 converts a [tuple.Tuple10[SeqEither[E, T]]] into a [SeqEither[E, tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]

func StopOnLeft added in v2.3.0

func StopOnLeft[E, T any](s SeqEither[E, T]) SeqEither[E, T]

func Swap

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

Swap exchanges the error and success type parameters of an SeqEither

func TakeUntilLeft added in v2.3.0

func TakeUntilLeft[E, T any](s SeqEither[E, T]) SeqEither[E, T]

TakeUntilLeft takes elements from a SeqEither until the first Left (error) is encountered, including that Left.

This function creates a transformation that yields all Right values from the source sequence until a Left value is encountered. When a Left is found, it is included in the output and the sequence terminates immediately. This is useful for processing sequences that should stop at the first error while still capturing that error.

The operation is lazy and only consumes elements from the source sequence as needed. Once a Left is encountered, iteration stops immediately without consuming the remaining elements from the source.

Marble Diagram:

Input:  --R(1)--R(2)--R(3)--L(e)--R(4)--R(5)-->
TakeUntilLeft
Output: --R(1)--R(2)--R(3)--L(e)|
                              (includes Left, then stops)

Where R(x) represents Right(x) and L(e) represents Left(e).

Type Parameters:

  • E: The error type (Left)
  • T: The success type (Right)

Parameters:

  • s: The input SeqEither to process

Returns:

  • SeqEither[E, T]: A sequence containing all Right values up to and including the first Left

Example - Stop at first error:

seq := iter.From(
    either.Right[string](1),
    either.Right[string](2),
    either.Left[int]("error"),
    either.Right[string](3),
)
result := TakeUntilLeft(seq)
// yields: Right(1), Right(2), Left("error")
// Note: Right(3) is not processed

Example - All Right values:

seq := iter.From(
    either.Right[string](1),
    either.Right[string](2),
    either.Right[string](3),
)
result := TakeUntilLeft(seq)
// yields: Right(1), Right(2), Right(3)
// All elements pass through since there's no Left

Example - First element is Left:

seq := iter.From(
    either.Left[int]("immediate error"),
    either.Right[string](1),
    either.Right[string](2),
)
result := TakeUntilLeft(seq)
// yields: Left("immediate error")
// Stops immediately after the first Left

Example - Processing with error handling:

parseNumbers := func(inputs []string) SeqEither[error, int] {
    seq := iter.MonadMap(
        iter.FromSlice(inputs),
        result.Eitherize1(strconv.Atoi),
    )
    return TakeUntilLeft(seq)
}
// Processes strings until first parse error, including the error

See Also:

  • iter.TakeWhileInclusive: The underlying iterator function used
  • either.IsRight: The predicate used to identify Right values

type Trampoline

type Trampoline[B, L any] = tailrec.Trampoline[B, L]

Trampoline represents a tail-recursive computation that can be evaluated safely without stack overflow. It's used for implementing stack-safe recursive algorithms.

type Void

type Void = function.Void

Void represents the absence of a value, similar to void in other languages. It's used in functions that perform side effects but don't return meaningful values. The zero value is function.VOID.

Example:

logMessage := func() Void {
    fmt.Println("Logging...")
    return function.VOID
}

Jump to

Keyboard shortcuts

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