Skip to main content

seqerr

import "github.com/go-softwarelab/common/pkg/seqerr"

Package seqerr provides specialized utilities for handling errors when working with iter.Seq in Go applications.

The goal of this package is to simplify error handling in sequence processing pipelines by offering functions that work with iter.Seq2 where the second value represents an error. These utilities automatically break iteration when an error is encountered and propagate it through the processing chain, allowing errors to be collected and handled at the end of the pipeline.

The package includes error-aware versions of common sequence operations such as mapping, filtering, and reducing, enabling developers to write clean and robust sequence processing code without explicitly handling errors at each step. This approach reduces boilerplate code and improves readability by separating the error handling logic from the business logic.

By integrating seamlessly with the iter.Seq ecosystem, this package provides a consistent way to manage errors across sequence operations, making it easier to build reliable data processing pipelines.

Append

func Append[E any](seq iter.Seq2[E, error], elem E) iter.Seq2[E, error]

Append appends element to the end of a sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq"
"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with numbers 1-3
sequence := seq.Range(1, 4)

// Append number 4 to the sequence
appended := seqerr.Append(seqerr.FromSeq(sequence), 4)

// Collect results
for n, err := range appended {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

1
2
3
4

Collect

func Collect[E any](seq iter.Seq2[E, error]) ([]E, error)

Collect collects the elements of the given sequence into a slice.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with numbers 1-3
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 3; i++ {
if !yield(i, nil) {
break
}
}
})

// Collect elements into a new slice
result, err := seqerr.Collect(sequence)
if err != nil {
fmt.Printf("Error: %v\n", err)
}

fmt.Println(result)

}

Output

[1 2 3]
Example (With Error)
package main

import (
"errors"
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with an error
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 3; i++ {
var err error
if i == 2 {
err = errors.New("source error")
}
if !yield(i, err) {
break
}
}
})

// Collect elements into a new slice
result, err := seqerr.Collect(sequence)
if err != nil {
fmt.Printf("Error: %v\n", err)
}

fmt.Println(result)

}

Output

Error: source error
[1]

Concat

func Concat[E any](sequences ...iter.Seq2[E, error]) iter.Seq2[E, error]

Concat concatenates multiple sequences into a single sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq"
"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create first sequence with numbers 1-2
first := seqerr.FromSeq(seq.Range(1, 3))

// Create second sequence with numbers 3-4
second := seqerr.FromSeq(seq.Range(3, 5))

// Concatenate the two sequences
combined := seqerr.Concat(first, second)

// Collect results
for n, err := range combined {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

1
2
3
4
Example (With Error)
package main

import (
"errors"
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create first sequence with an error
first := iter.Seq2[int, error](func(yield func(int, error) bool) {
if !yield(1, nil) {
return
}
if !yield(2, errors.New("first sequence error")) {
return
}
// This won't be processed due to the error
if !yield(3, nil) {
return
}
})

// Create second sequence
second := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 4; i <= 5; i++ {
if !yield(i, nil) {
break
}
}
})

// Concatenate the two sequences
combined := seqerr.Concat(first, second)

// Collect results
for n, err := range combined {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

1
Error: first sequence error

Count

func Count[E any](seq iter.Seq2[E, error]) (int, error)

Count returns the number of elements in the sequence.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with numbers 1-3
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 3; i++ {
if !yield(i, nil) {
break
}
}
})

// Count elements in the sequence
count, err := seqerr.Count(sequence)
if err != nil {
fmt.Printf("Error: %v\n", err)
}

fmt.Println(count)

}

Output

3
Example (With Error)
package main

import (
"errors"
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with an error
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 3; i++ {
var err error
if i == 2 {
err = errors.New("source error")
}
if !yield(i, err) {
break
}
}
})

// Count elements in the sequence
count, err := seqerr.Count(sequence)
if err != nil {
fmt.Printf("Error: %v\n", err)
}

fmt.Println(count)

}

Output

Error: source error
0

Each

func Each[E any, C Consumer[E]](seq iter.Seq2[E, error], consumer C) iter.Seq2[E, error]

Each returns a sequence that applies the given consumer to each element of the input sequence and pass it further. Each is an alias for Tap. Comparing to ForEach, this is a lazy function and doesn't consume the input sequence.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with numbers 1-3
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 3; i++ {
if !yield(i, nil) {
break
}
}
})

// Use Each (alias for Tap) to print each element while passing it through
each := seqerr.Each(sequence, func(n int) {
fmt.Printf("Element: %d\n", n)
})

// Collect the elements after processing
result, err := seqerr.Collect(each)
if err != nil {
fmt.Printf("Error: %v\n", err)
}

fmt.Println("Result:", result)

}

Output

Element: 1
Element: 2
Element: 3
Result: [1 2 3]

Filter

func Filter[E any, P Predicate[E]](seq iter.Seq2[E, error], predicate P) iter.Seq2[E, error]

Filter returns a new sequence that contains only the elements that satisfy the predicate.

Example (Predicate With Error)
package main

import (
"fmt"
"iter"
"strconv"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
sequence := iter.Seq2[string, error](func(yield func(string, error) bool) {
for i := range 5 {
if !yield(fmt.Sprintf("%d", i), nil) {
break
}
}
})

// Filter strings that are even numbers when converted to int
filtered := seqerr.Filter(sequence, func(s string) (bool, error) {
i, err := strconv.Atoi(s)
if err != nil {
return false, err
}
return i%2 == 0, nil
})

// Print results
for s, err := range filtered {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(s)
}

}

Output

0
2
4
Example (Predicate Without Error)
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := range 5 {
yield(i, nil)
}
})

// Filter even numbers
evenNumbers := seqerr.Filter(sequence, func(n int) bool {
return n%2 == 0
})

// Print results
for n, err := range evenNumbers {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

0
2
4
Example (Source Error)
package main

import (
"errors"
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence that produces an error
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := range 5 {
var err error
if i == 2 {
err = errors.New("source error")
}
if !yield(i, err) {
break
}
}
})

// Filter even numbers
filtered := seqerr.Filter(sequence, func(n int) bool {
return n%2 == 0
})

// Collect results
for n, err := range filtered {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

0
Error: source error
Example (Validator)
package main

import (
"errors"
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := range 5 {
if !yield(i+1, nil) {
break
}
}
})

// Filter using a validator (non-zero values)
nonZero := seqerr.Filter(sequence, func(n int) error {
if n%2 == 0 {
return errors.New("even value not allowed")
}
return nil
})

// Collect results
for n, err := range nonZero {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

1
Error: even value not allowed

FlatMap

func FlatMap[E any, R any](seq iter.Seq2[E, error], mapper MapperWithoutError[E, iter.Seq[R]]) iter.Seq2[R, error]

FlatMap applies a mapper function to each element of the sequence and flattens the result.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seq"
"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with numbers 1-3
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 3; i++ {
if !yield(i, nil) {
break
}
}
})

// FlatMap to create duplicates of each number
duplicated := seqerr.FlatMap(sequence, func(n int) iter.Seq[int] {
return seq.Repeat(n, 2)
})

// Collect results
for n, err := range duplicated {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

1
1
2
2
3
3

FlatMapOrErr

func FlatMapOrErr[E any, R any](seq iter.Seq2[E, error], mapper MapperWithError[E, iter.Seq[R]]) iter.Seq2[R, error]

FlatMapOrErr applies a mapper function that can return error to each element of the sequence and flattens the result.

Example
package main

import (
"fmt"
"iter"
"strconv"

"github.com/go-softwarelab/common/pkg/seq"
"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence of strings
sequence := iter.Seq2[string, error](func(yield func(string, error) bool) {
for i := 1; i <= 3; i++ {
var value string
if i == 2 {
value = "two"
} else {
value = strconv.Itoa(i)
}
if !yield(value, nil) {
break
}
}
})

// Duplicate integers or return an error if cannot be parsed
numbers := seqerr.FlatMapOrErr(sequence, func(s string) (iter.Seq[int], error) {
i, err := strconv.Atoi(s)
if err != nil {
return nil, err
}
return seq.Repeat(i, 2), nil
})

// Collect results
for n, err := range numbers {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

1
1
Error: strconv.Atoi: parsing "two": invalid syntax

Flatten

func Flatten[Seq iter.Seq2[iter.Seq[E], error], E any](seq Seq) iter.Seq2[E, error]

Flatten flattens a sequence of sequences.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seq"
"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence of sequences
sequence := seq.RangeTo(3)

seqOfSeq := seqerr.MapSeq(sequence, func(n int) (iter.Seq[int], error) {
return seq.Repeat(n, 2), nil
})

// Flatten the sequence of sequences
flattened := seqerr.Flatten(seqOfSeq)

// Collect results
for n, err := range flattened {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

0
0
1
1
2
2

FlattenSlices

func FlattenSlices[Seq iter.Seq2[[]E, error], E any](seq Seq) iter.Seq2[E, error]

FlattenSlices flattens a sequence of slices.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence of slices
sequence := iter.Seq2[[]int, error](func(yield func([]int, error) bool) {
slices := [][]int{{1, 2}, {3, 4, 5}, {6}}
for _, slice := range slices {
if !yield(slice, nil) {
break
}
}
})

// Flatten the sequence of slices
flattened := seqerr.FlattenSlices(sequence)

// Collect results
for n, err := range flattened {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

1
2
3
4
5
6
Example (With Error)
package main

import (
"errors"
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence of slices with an error
sequence := iter.Seq2[[]int, error](func(yield func([]int, error) bool) {
if !yield([]int{1, 2}, nil) {
return
}
if !yield(nil, errors.New("slice error")) {
return
}
// This won't be processed due to the error
if !yield([]int{3, 4}, nil) {
return
}
})

// Flatten the sequence of slices
flattened := seqerr.FlattenSlices(sequence)

// Collect results
for n, err := range flattened {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

1
2
Error: slice error

Fold

func Fold[E any](seq iter.Seq2[E, error], accumulator func(agg E, item E) E) (optional.Value[E], error)

Fold applies a function against an accumulator and each element in the sequence (from left to right) to reduce it to a single value.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with numbers
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 5; i++ {
if !yield(i, nil) {
break
}
}
})

// Calculate the product of all numbers
result, err := seqerr.Fold(sequence, func(acc int, item int) int {
return acc * item
})

if err != nil {
fmt.Printf("Error: %v\n", err)
}

if result.IsPresent() {
fmt.Println("Product:", result.MustGet())
} else {
fmt.Println("Empty sequence")
}

}

Output

Product: 120
Example (Empty Sequence)
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create an empty sequence
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
// Do nothing
})

// Try to fold the empty sequence
result, err := seqerr.Fold(sequence, func(acc int, item int) int {
return acc + item
})

if err != nil {
fmt.Printf("Error: %v\n", err)
}

if result.IsPresent() {
fmt.Println("Sum:", result.MustGet())
} else {
fmt.Println("Empty sequence")
}

}

Output

Empty sequence

FoldRight

func FoldRight[E any](seq iter.Seq2[E, error], accumulator func(agg E, item E) E) (optional.Value[E], error)

FoldRight applies a function against an accumulator and each element in the sequence (from right to left) to reduce it to a single value.

Example
package main

import (
"fmt"
"iter"
"strings"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with strings
sequence := iter.Seq2[string, error](func(yield func(string, error) bool) {
words := []string{"hello", "world"}
for _, word := range words {
if !yield(word, nil) {
break
}
}
})

// Concatenate strings right-to-left
result, err := seqerr.FoldRight(sequence, func(acc string, item string) string {
return strings.ToUpper(acc) + "-" + item
})

if err != nil {
fmt.Printf("Error: %v\n", err)
}

if result.IsPresent() {
fmt.Println(result.MustGet())
} else {
fmt.Println("Empty sequence")
}

}

Output

WORLD-hello

ForEach

func ForEach[E any, C Consumer[E]](seq iter.Seq2[E, error], consumer C) error

ForEach applies consumer to each element of the input sequence. Comparing to Each, this is not a lazy function and consumes the input sequence.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with numbers 1-3
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 3; i++ {
if !yield(i, nil) {
break
}
}
})

// Use ForEach to process all elements
sum := 0
err := seqerr.ForEach(sequence, func(n int) {
fmt.Printf("Adding: %d\n", n)
sum += n
})

if err != nil {
fmt.Printf("Error: %v\n", err)
}

fmt.Println("Sum:", sum)

}

Output

Adding: 1
Adding: 2
Adding: 3
Sum: 6
Example (With Consumer Error)
package main

import (
"errors"
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with numbers 1-3
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 3; i++ {
if !yield(i, nil) {
break
}
}
})

// Use ForEach with a consumer that returns an error
sum := 0
err := seqerr.ForEach(sequence, func(n int) error {
if n == 2 {
return errors.New("consumer error")
}
fmt.Printf("Adding: %d\n", n)
sum += n
return nil
})

if err != nil {
fmt.Printf("Error: %v\n", err)
}

fmt.Println("Sum:", sum)

}

Output

Adding: 1
Error: consumer error
Sum: 1
Example (With Error)
package main

import (
"errors"
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with numbers 1-3
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 3; i++ {
var err error
if i == 2 {
err = errors.New("source error")
}
if !yield(i, err) {
break
}
}
})

// Use ForEach to process elements
sum := 0
err := seqerr.ForEach(sequence, func(n int) {
fmt.Printf("Adding: %d\n", n)
sum += n
})

if err != nil {
fmt.Printf("Error: %v\n", err)
}

fmt.Println("Sum:", sum)

}

Output

Adding: 1
Error: source error
Sum: 1

FromSeq

func FromSeq[E any](sequence iter.Seq[E]) iter.Seq2[E, error]

FromSeq converts a sequence of elements into a sequence of elements and nil errors.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence without errors first
originalSeq := func(yield func(int) bool) {
for i := 1; i <= 3; i++ {
if !yield(i) {
break
}
}
}

// Convert to sequence with error handling
sequence := seqerr.FromSeq(originalSeq)

for item, err := range sequence {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(item)
}

}

Output

1
2
3

FromSlice

func FromSlice[E any](slice []E) iter.Seq2[E, error]

FromSlice converts a slice of elements into a sequence of elements and nil errors.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
slice := []string{"a", "b", "c"}
sequence := seqerr.FromSlice(slice)

for item, err := range sequence {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(item)
}

}

Output

a
b
c

Map

func Map[E any, R any](seq iter.Seq2[E, error], mapper MapperWithoutError[E, R]) iter.Seq2[R, error]

Map applies a mapper function to each element of the sequence.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with numbers 1-3
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 3; i++ {
yield(i, nil)
}
})

// Map numbers to their squares
squared := seqerr.Map(sequence, func(n int) int {
return n * n
})

// Collect results
for n, err := range squared {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

1
4
9
Example (Source Error)
package main

import (
"errors"
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with error
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 3; i++ {
var err error
if i == 2 {
err = errors.New("source error")
}
if !yield(i, err) {
break
}
}
})

// Map numbers to their squares
squared := seqerr.Map(sequence, func(n int) int {
return n * n
})

// Collect results
for n, err := range squared {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

1
Error: source error

MapOrErr

func MapOrErr[E any, R any](seq iter.Seq2[E, error], mapper MapperWithError[E, R]) iter.Seq2[R, error]

MapOrErr applies a mapper function that can return error to each element of the sequence.

Example
package main

import (
"fmt"
"iter"
"strconv"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence of strings
sequence := iter.Seq2[string, error](func(yield func(string, error) bool) {
for i := 1; i <= 3; i++ {
var value string
if i == 2 {
value = "two"
} else {
value = strconv.Itoa(i)
}
if !yield(value, nil) {
break
}
}
})

// Map strings to integers
numbers := seqerr.MapOrErr(sequence, func(s string) (int, error) {
return strconv.Atoi(s)
})

// Collect results
for n, err := range numbers {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

1
Error: strconv.Atoi: parsing "two": invalid syntax

MapSeq

func MapSeq[E any, R any](seq iter.Seq[E], mapper MapperWithError[E, R]) iter.Seq2[R, error]

MapSeq applies a mapper function to each element of the sequence. The mapper function can return an error.

Of

func Of[E any](elements ...E) iter.Seq2[E, error]

Of creates a new sequence of elements and nil errors, from the provided elements.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
sequence := seqerr.Of(1, 2, 3)

for item, err := range sequence {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(item)
}

}

Output

1
2
3

Prepend

func Prepend[E any](seq iter.Seq2[E, error], elem E) iter.Seq2[E, error]

Prepend prepends element to the beginning of a sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq"
"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with numbers 2-4
sequence := seq.Range(2, 5)

// Prepend number 1 to the sequence
prepended := seqerr.Prepend(seqerr.FromSeq(sequence), 1)

// Collect results
for n, err := range prepended {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

1
2
3
4

Produce

func Produce[E, A any](next func(A) ([]E, A, error)) iter.Seq2[[]E, error]

Produce returns a new sequence that is filled by the results of calling the next function.

Example
package main

import (
"fmt"
"strconv"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
sequence := seqerr.Produce(func(i int) ([]string, int, error) {
if i == 2 {
return []string{}, i + 1, nil
}

num := strconv.Itoa(i)
result := []string{"a" + num, "b" + num, "c" + num}
return result, i + 1, nil
})

for item, err := range sequence {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(item)
}

}

Output

[a0 b0 c0]
[a1 b1 c1]

ProduceWithArg

func ProduceWithArg[E, A any](next func(A) ([]E, A, error), arg A) iter.Seq2[[]E, error]

ProduceWithArg returns a new sequence that is filled by the results of calling the next function with the provided argument.

Example
package main

import (
"fmt"
"strconv"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
sequence := seqerr.ProduceWithArg(func(i int) ([]string, int, error) {
if i == 2 {
return []string{}, i + 1, nil
}

num := strconv.Itoa(i)
result := []string{"a" + num, "b" + num, "c" + num}
return result, i + 1, nil
}, 1)

for item, err := range sequence {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(item)
}

}

Output

[a1 b1 c1]

Reduce

func Reduce[E any, R any](seq iter.Seq2[E, error], accumulator func(agg R, item E) R, initial R) (R, error)

Reduce applies a function against an accumulator and each element in the sequence (from left to right) to reduce it to a single value.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with numbers 1-5
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 5; i++ {
if !yield(i, nil) {
break
}
}
})

// Sum all numbers
sum, err := seqerr.Reduce(sequence, func(acc int, item int) int {
return acc + item
}, 0)

if err != nil {
fmt.Printf("Error: %v\n", err)
}
fmt.Println("Sum:", sum)

}

Output

Sum: 15
Example (With Error)
package main

import (
"errors"
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with an error
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 5; i++ {
var err error
if i == 3 {
err = errors.New("source error")
}
if !yield(i, err) {
break
}
}
})

// Sum all numbers
sum, err := seqerr.Reduce(sequence, func(acc int, item int) int {
return acc + item
}, 0)

if err != nil {
fmt.Printf("Error: %v\n", err)
}
fmt.Println("Sum:", sum)

}

Output

Error: source error
Sum: 0

ReduceRight

func ReduceRight[E any, R any](seq iter.Seq2[E, error], accumulator func(agg R, item E) R, initial R) (R, error)

ReduceRight applies a function against an accumulator and each element in the sequence (from right to left) to reduce it to a single value.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with words
sequence := iter.Seq2[string, error](func(yield func(string, error) bool) {
words := []string{"hello", "beautiful", "world"}
for _, word := range words {
if !yield(word, nil) {
break
}
}
})

// Join words right-to-left
joined, err := seqerr.ReduceRight(sequence, func(acc string, item string) string {
if acc == "" {
return item
}
return item + " " + acc
}, "")

if err != nil {
fmt.Printf("Error: %v\n", err)
}
fmt.Println(joined)

}

Output

hello beautiful world

Take

func Take[E any](seq iter.Seq2[E, error], n int) iter.Seq2[E, error]

Take returns a new sequence that contains only the first n elements of the given sequence.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence of numbers
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := range 10 {
if !yield(i, nil) {
break
}
}
})

// Take only the first 3 elements
taken := seqerr.Take(sequence, 3)

// Print results
for n, err := range taken {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

0
1
2

TakeUntil

func TakeUntil[E any, P Predicate[E]](seq iter.Seq2[E, error], predicate P) iter.Seq2[E, error]

TakeUntil returns a new sequence that takes elements from the given sequence until the predicate is satisfied.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence of numbers
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 0; i < 10; i++ {
if !yield(i, nil) {
break
}
}
})

// Take elements until we find one that's equal to 5
taken := seqerr.TakeUntil(sequence, func(n int) bool {
return n == 5
})

// Print results
for n, err := range taken {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

0
1
2
3
4

TakeUntilTrue

func TakeUntilTrue[E any](seq iter.Seq2[E, error], stopCondition func() bool) iter.Seq2[E, error]

TakeUntilTrue returns a new sequence that takes elements from the given sequence until the stop condition is satisfied. If condition is met before the first element, the sequence will not yield any elements.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence of numbers
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 0; i < 10; i++ {
if !yield(i, nil) {
break
}
}
})

// Create a condition that true
condition := func() bool {
return true
}

// Take elements until the condition becomes true
taken := seqerr.TakeUntilTrue(sequence, condition)

// Print results
for n, err := range taken {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

TakeWhile

func TakeWhile[E any, P Predicate[E]](seq iter.Seq2[E, error], predicate P) iter.Seq2[E, error]

TakeWhile returns a new sequence that takes elements from the given sequence while the predicate is satisfied.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence of numbers
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 0; i < 10; i++ {
if !yield(i, nil) {
break
}
}
})

// Take elements while they are less than 5
taken := seqerr.TakeWhile(sequence, func(n int) bool {
return n < 5
})

// Print results
for n, err := range taken {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

0
1
2
3
4

TakeWhileTrue

func TakeWhileTrue[E any](seq iter.Seq2[E, error], continueCondition func() bool) iter.Seq2[E, error]

TakeWhileTrue returns a new sequence that takes elements from the given sequence while the stop condition is satisfied. If condition is met before the first element, the sequence will not yield any elements.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence of numbers
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 0; i < 10; i++ {
if !yield(i, nil) {
break
}
}
})

// Create a condition that false
condition := func() bool {
return false
}

// Take elements while the condition remains true
taken := seqerr.TakeWhileTrue(sequence, condition)

// Print results
for n, err := range taken {
if err != nil {
fmt.Printf("Error: %v\n", err)
break
}
fmt.Println(n)
}

}

Output

Tap

func Tap[E any, C Consumer[E]](seq iter.Seq2[E, error], consumer C) iter.Seq2[E, error]

Tap returns a sequence that applies the given consumer to each element of the input sequence and pass it further. In case if consumer returns an error, the sequence stops and pass only the error from consumer further.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with numbers 1-3
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 3; i++ {
if !yield(i, nil) {
break
}
}
})

// Use Tap to print each element while passing it through
tapped := seqerr.Tap(sequence, func(n int) {
fmt.Printf("Processing: %d\n", n)
})

// Collect the elements after tapping
result, err := seqerr.Collect(tapped)
if err != nil {
fmt.Printf("Error: %v\n", err)
}

fmt.Println("Result:", result)

}

Output

Processing: 1
Processing: 2
Processing: 3
Result: [1 2 3]
Example (With Error)
package main

import (
"errors"
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 3; i++ {
if !yield(i, nil) {
break
}
}
})

// Use Tap with a consumer that returns an error
tapped := seqerr.Tap(sequence, func(n int) error {
if n == 2 {
return errors.New("consumer error")
}
fmt.Printf("Processing: %d\n", n)
return nil
})

// Collect the elements after tapping
result, err := seqerr.Collect(tapped)
if err != nil {
fmt.Printf("Error: %v\n", err)
}

fmt.Println("Result:", result)

}

Output

Processing: 1
Error: consumer error
Result: [1]

ToSlice

func ToSlice[Slice ~[]E, E any](seq iter.Seq2[E, error], slice Slice) (Slice, error)

ToSlice collects the elements of the given sequence into a slice.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with numbers 1-3
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 3; i++ {
if !yield(i, nil) {
break
}
}
})

// Collect elements into a slice
slice, err := seqerr.ToSlice(sequence, make([]int, 0))
if err != nil {
fmt.Printf("Error: %v\n", err)
}

fmt.Println(slice)

}

Output

[1 2 3]
Example (With Error)
package main

import (
"errors"
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seqerr"
)

func main() {
// Create a sequence with an error
sequence := iter.Seq2[int, error](func(yield func(int, error) bool) {
for i := 1; i <= 3; i++ {
var err error
if i == 2 {
err = errors.New("source error")
}
if !yield(i, err) {
break
}
}
})

// Collect elements into a slice
slice, err := seqerr.ToSlice(sequence, make([]int, 0))
if err != nil {
fmt.Printf("Error: %v\n", err)
}

fmt.Println(slice)

}

Output

Error: source error
[1]

type Consumer

Consumer is a function that is consuming the sequence.

type Consumer[E any] interface {
// contains filtered or unexported methods
}

type ConsumerWithError

ConsumerWithError is a function that takes an element and returns an error.

type ConsumerWithError[E any] = func(E) error

type ConsumerWithoutError

ConsumerWithoutError is a function that takes an element and returns nothing.

type ConsumerWithoutError[E any] = func(E)

type Mapper

Mapper is a function that takes an element and returns a result. It can return an error.

type Mapper[E any, R any] interface {
// contains filtered or unexported methods
}

type MapperWithError

MapperWithError is a function that takes an element and returns a result and an error.

type MapperWithError[E any, R any] = func(E) (R, error)

type MapperWithoutError

MapperWithoutError is a function that takes an element and returns a result.

type MapperWithoutError[E any, R any] = func(E) R

type Predicate

Predicate is a function that takes an element and returns a boolean. It can return an error.

type Predicate[E any] interface {
// contains filtered or unexported methods
}

type PredicateWithError

PredicateWithError is a function that takes an element and returns a boolean, it can fail with error.

type PredicateWithError[E any] = func(E) (bool, error)

type PredicateWithoutError

PredicateWithoutError is a function that takes an element and returns a boolean.

type PredicateWithoutError[E any] = func(E) bool

type Validator

Validator is a function that takes an element and returns an error.

type Validator[E any] = func(E) error