array

package
v2.0.1 Latest Latest
Warning

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

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

Documentation

Overview

Package array provides functional programming utilities for working with Go slices.

This package treats Go slices as immutable arrays and provides a rich set of operations for transforming, filtering, folding, and combining arrays in a functional style. All operations return new arrays rather than modifying existing ones.

Core Concepts

The array package implements several functional programming abstractions:

  • Functor: Transform array elements with Map
  • Applicative: Apply functions in arrays to values in arrays
  • Monad: Chain operations that produce arrays with Chain/FlatMap
  • Foldable: Reduce arrays to single values with Reduce/Fold
  • Traversable: Transform arrays while preserving structure

Basic Operations

// Creating arrays
arr := array.From(1, 2, 3, 4, 5)
repeated := array.Replicate(3, "hello")
generated := array.MakeBy(5, func(i int) int { return i * 2 })

// Transforming arrays
doubled := array.Map(N.Mul(2))(arr)
filtered := array.Filter(func(x int) bool { return x > 2 })(arr)

// Combining arrays
combined := array.Flatten([][]int{{1, 2}, {3, 4}})
zipped := array.Zip([]string{"a", "b"})([]int{1, 2})

Mapping and Filtering

Transform array elements with Map, or filter elements with Filter:

numbers := []int{1, 2, 3, 4, 5}

// Map transforms each element
doubled := array.Map(N.Mul(2))(numbers)
// Result: [2, 4, 6, 8, 10]

// Filter keeps elements matching a predicate
evens := array.Filter(func(x int) bool { return x%2 == 0 })(numbers)
// Result: [2, 4]

// FilterMap combines both operations
import "github.com/IBM/fp-go/v2/option"
result := array.FilterMap(func(x int) option.Option[int] {
    if x%2 == 0 {
        return option.Some(x * 2)
    }
    return option.None[int]()
})(numbers)
// Result: [4, 8]

Folding and Reducing

Reduce arrays to single values:

numbers := []int{1, 2, 3, 4, 5}

// Sum all elements
sum := array.Reduce(func(acc, x int) int { return acc + x }, 0)(numbers)
// Result: 15

// Using a Monoid
import "github.com/IBM/fp-go/v2/monoid"
sum := array.Fold(monoid.MonoidSum[int]())(numbers)
// Result: 15

Chaining Operations

Chain operations that produce arrays (also known as FlatMap):

numbers := []int{1, 2, 3}
result := array.Chain(func(x int) []int {
    return []int{x, x * 10}
})(numbers)
// Result: [1, 10, 2, 20, 3, 30]

Finding Elements

Search for elements matching predicates:

numbers := []int{1, 2, 3, 4, 5}

// Find first element > 3
first := array.FindFirst(func(x int) bool { return x > 3 })(numbers)
// Result: Some(4)

// Find last element > 3
last := array.FindLast(func(x int) bool { return x > 3 })(numbers)
// Result: Some(5)

// Get head and tail
head := array.Head(numbers) // Some(1)
tail := array.Tail(numbers) // Some([2, 3, 4, 5])

Sorting

Sort arrays using Ord instances:

import "github.com/IBM/fp-go/v2/ord"

numbers := []int{3, 1, 4, 1, 5}
sorted := array.Sort(ord.FromStrictCompare[int]())(numbers)
// Result: [1, 1, 3, 4, 5]

// Sort by extracted key
type Person struct { Name string; Age int }
people := []Person{{"Alice", 30}, {"Bob", 25}}
byAge := array.SortByKey(ord.FromStrictCompare[int](), func(p Person) int {
    return p.Age
})(people)

Uniqueness

Remove duplicate elements:

numbers := []int{1, 2, 2, 3, 3, 3}
unique := array.StrictUniq(numbers)
// Result: [1, 2, 3]

// Unique by key
type Person struct { Name string; Age int }
people := []Person{{"Alice", 30}, {"Bob", 25}, {"Alice", 35}}
uniqueByName := array.Uniq(func(p Person) string { return p.Name })(people)
// Result: [{"Alice", 30}, {"Bob", 25}]

Zipping

Combine multiple arrays:

names := []string{"Alice", "Bob", "Charlie"}
ages := []int{30, 25, 35}

// Zip into tuples
pairs := array.Zip(ages)(names)
// Result: [(Alice, 30), (Bob, 25), (Charlie, 35)]

// Zip with custom function
result := array.ZipWith(names, ages, func(name string, age int) string {
    return fmt.Sprintf("%s is %d", name, age)
})

Monadic Do Notation

Build complex array computations using do-notation style:

result := array.Do(
    struct{ X, Y int }{},
)(
    array.Bind(
        func(x int) func(s struct{}) struct{ X int } {
            return func(s struct{}) struct{ X int } { return struct{ X int }{x} }
        },
        func(s struct{}) []int { return []int{1, 2, 3} },
    ),
    array.Bind(
        func(y int) func(s struct{ X int }) struct{ X, Y int } {
            return func(s struct{ X int }) struct{ X, Y int } {
                return struct{ X, Y int }{s.X, y}
            }
        },
        func(s struct{ X int }) []int { return []int{4, 5} },
    ),
)
// Produces all combinations: [{1,4}, {1,5}, {2,4}, {2,5}, {3,4}, {3,5}]

Sequence and Traverse

Transform arrays of effects into effects of arrays:

import "github.com/IBM/fp-go/v2/option"

// Sequence: []Option[A] -> Option[[]A]
opts := []option.Option[int]{
    option.Some(1),
    option.Some(2),
    option.Some(3),
}
result := array.ArrayOption[int]()(opts)
// Result: Some([1, 2, 3])

// If any is None, result is None
opts2 := []option.Option[int]{
    option.Some(1),
    option.None[int](),
    option.Some(3),
}
result2 := array.ArrayOption[int]()(opts2)
// Result: None

Equality and Comparison

Compare arrays for equality:

import "github.com/IBM/fp-go/v2/eq"

eq := array.Eq(eq.FromStrictEquals[int]())
equal := eq.Equals([]int{1, 2, 3}, []int{1, 2, 3})
// Result: true

Monoid Operations

Combine arrays using monoid operations:

import "github.com/IBM/fp-go/v2/monoid"

// Concatenate arrays
m := array.Monoid[int]()
result := m.Concat([]int{1, 2}, []int{3, 4})
// Result: [1, 2, 3, 4]

// Concatenate multiple arrays efficiently
result := array.ArrayConcatAll(
    []int{1, 2},
    []int{3, 4},
    []int{5, 6},
)
// Result: [1, 2, 3, 4, 5, 6]

Performance Considerations

Most operations create new arrays rather than modifying existing ones. For performance-critical code, consider:

  • Using Copy for shallow copies when needed
  • Using Clone with a custom cloning function for deep copies
  • Batching operations to minimize intermediate allocations
  • Using ArrayConcatAll for efficient concatenation of multiple arrays

Subpackages

  • array/generic: Generic implementations for custom array-like types
  • array/nonempty: Operations for non-empty arrays with compile-time guarantees
  • array/testing: Testing utilities for array laws and properties
Example (Any)
pred := func(val int) bool {
	return val&2 == 0
}

data1 := From(1, 2, 3)

fmt.Println(Any(pred)(data1))
Output:

true
Example (Any_filter)
pred := func(val int) bool {
	return val&2 == 0
}

data1 := From(1, 2, 3)

// Any tests if any of the entries in the array matches the condition
Any := F.Flow2(
	Filter(pred),
	IsNonEmpty[int],
)

fmt.Println(Any(data1))
Output:

true
Example (Any_find)
pred := func(val int) bool {
	return val&2 == 0
}

data1 := From(1, 2, 3)

// Any tests if any of the entries in the array matches the condition
Any := F.Flow2(
	FindFirst(pred),
	O.IsSome[int],
)

fmt.Println(Any(data1))
Output:

true
Example (Basic)

Example_basic adapts examples from [https://github.com/inato/fp-ts-cheatsheet#basic-manipulation]

someArray := From(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) // []int

isEven := func(num int) bool {
	return num%2 == 0
}

square := func(num int) int {
	return num * num
}

// filter and map
result := F.Pipe2(
	someArray,
	Filter(isEven),
	Map(square),
) // [0 4 16 36 64]

// or in one go with filterMap
resultFilterMap := F.Pipe1(
	someArray,
	FilterMap(
		F.Flow2(O.FromPredicate(isEven), O.Map(square)),
	),
)

fmt.Println(result)
fmt.Println(resultFilterMap)
Output:

[0 4 16 36 64]
[0 4 16 36 64]
Example (Find)
pred := func(val int) bool {
	return val&2 == 0
}

data1 := From(1, 2, 3)

fmt.Println(FindFirst(pred)(data1))
Output:

Some[int](1)
Example (Find_filter)
pred := func(val int) bool {
	return val&2 == 0
}

data1 := From(1, 2, 3)

Find := F.Flow2(
	Filter(pred),
	Head[int],
)

fmt.Println(Find(data1))
Output:

Some[int](1)
Example (Sort)

Example_sort adapts examples from [https://github.com/inato/fp-ts-cheatsheet#sort-elements-with-ord]

package main

import (
	"fmt"

	F "github.com/IBM/fp-go/v2/function"
	I "github.com/IBM/fp-go/v2/number/integer"
	O "github.com/IBM/fp-go/v2/option"
	"github.com/IBM/fp-go/v2/ord"
	S "github.com/IBM/fp-go/v2/string"
)

type user struct {
	name string
	age  O.Option[int]
}

func (user user) GetName() string {
	return user.name
}

func (user user) GetAge() O.Option[int] {
	return user.age
}

// Example_sort adapts examples from [https://github.com/inato/fp-ts-cheatsheet#sort-elements-with-ord]
func main() {

	strings := From("zyx", "abc", "klm")

	sortedStrings := F.Pipe1(
		strings,
		Sort(S.Ord),
	) // => ['abc', 'klm', 'zyx']

	// reverse sort
	reverseSortedStrings := F.Pipe1(
		strings,
		Sort(ord.Reverse(S.Ord)),
	) // => ['zyx', 'klm', 'abc']

	// sort Option
	optionalNumbers := From(O.Some(1337), O.None[int](), O.Some(42))

	sortedNums := F.Pipe1(
		optionalNumbers,
		Sort(O.Ord(I.Ord)),
	)

	// complex object with different rules
	byName := F.Pipe1(
		S.Ord,
		ord.Contramap(user.GetName),
	) // ord.Ord[user]

	byAge := F.Pipe1(
		O.Ord(I.Ord),
		ord.Contramap(user.GetAge),
	) // ord.Ord[user]

	sortedUsers := F.Pipe1(
		From(user{name: "a", age: O.Of(30)}, user{name: "d", age: O.Of(10)}, user{name: "c"}, user{name: "b", age: O.Of(10)}),
		SortBy(From(byAge, byName)),
	)

	fmt.Println(sortedStrings)
	fmt.Println(reverseSortedStrings)
	fmt.Println(sortedNums)
	fmt.Println(sortedUsers)

}
Output:

[abc klm zyx]
[zyx klm abc]
[None[int] Some[int](42) Some[int](1337)]
[{c {0 false}} {b {10 true}} {d {10 true}} {a {30 true}}]

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Any

func Any[A any](pred func(A) bool) func([]A) bool

Any tests if any of the elements in the array matches the predicate. Returns true if at least one element satisfies the predicate, false otherwise. Returns false for an empty array.

Example:

hasEven := array.Any(func(x int) bool { return x%2 == 0 })
result := hasEven([]int{1, 3, 4, 5}) // true

func AnyWithIndex

func AnyWithIndex[A any](pred func(int, A) bool) func([]A) bool

AnyWithIndex tests if any of the elements in the array matches the predicate. The predicate receives both the index and the element. Returns true if at least one element satisfies the predicate, false otherwise.

Example:

hasEvenAtEvenIndex := array.AnyWithIndex(func(i, x int) bool {
    return i%2 == 0 && x%2 == 0
})
result := hasEvenAtEvenIndex([]int{1, 3, 4, 5}) // true (4 is at index 2)

func Append

func Append[A any](as []A, a A) []A

Append adds an element to the end of an array, returning a new array.

func ArrayConcatAll

func ArrayConcatAll[A any](data ...[]A) []A

ArrayConcatAll efficiently concatenates multiple arrays into a single array. This function pre-allocates the exact amount of memory needed and performs a single copy operation for each input array, making it more efficient than repeated concatenations.

Example:

result := array.ArrayConcatAll(
    []int{1, 2},
    []int{3, 4},
    []int{5, 6},
) // [1, 2, 3, 4, 5, 6]

func ConcatAll

func ConcatAll[A any](m M.Monoid[A]) func([]A) A

ConcatAll concatenates all elements of an array using the provided Monoid. This reduces the array to a single value by repeatedly applying the Monoid's concat operation.

Example:

import "github.com/IBM/fp-go/v2/monoid"

// Sum all numbers
sumAll := array.ConcatAll(monoid.MonoidSum[int]())
result := sumAll([]int{1, 2, 3, 4, 5}) // 15

// Concatenate all strings
concatStrings := array.ConcatAll(monoid.MonoidString())
result2 := concatStrings([]string{"Hello", " ", "World"}) // "Hello World"

func ConstNil

func ConstNil[A any]() []A

ConstNil returns a nil array

func Copy

func Copy[A any](b []A) []A

Copy creates a shallow copy of the array

func Do

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

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

Example:

type State struct {
    X int
    Y int
}
result := array.Do(State{})

func Empty

func Empty[A any]() []A

Empty returns an empty array of type A.

func Eq

func Eq[T any](e E.Eq[T]) E.Eq[[]T]

Eq creates an equality checker for arrays given an equality checker for elements. Two arrays are considered equal if they have the same length and all corresponding elements are equal according to the provided Eq instance.

Example:

import "github.com/IBM/fp-go/v2/eq"

intArrayEq := array.Eq(eq.FromStrictEquals[int]())
result := intArrayEq.Equals([]int{1, 2, 3}, []int{1, 2, 3}) // true
result2 := intArrayEq.Equals([]int{1, 2, 3}, []int{1, 2, 4}) // false

func FindFirst

func FindFirst[A any](pred func(A) bool) option.Kleisli[[]A, A]

FindFirst finds the first element which satisfies a predicate function. Returns Some(element) if found, None if no element matches.

Example:

findGreaterThan3 := array.FindFirst(func(x int) bool { return x > 3 })
result := findGreaterThan3([]int{1, 2, 4, 5}) // Some(4)
result2 := findGreaterThan3([]int{1, 2, 3}) // None

func FindFirstMap

func FindFirstMap[A, B any](sel option.Kleisli[A, B]) option.Kleisli[[]A, B]

FindFirstMap finds the first element for which the selector function returns Some. This combines finding and mapping in a single operation.

Example:

import "strconv"

parseFirst := array.FindFirstMap(func(s string) option.Option[int] {
    if n, err := strconv.Atoi(s); err == nil {
        return option.Some(n)
    }
    return option.None[int]()
})
result := parseFirst([]string{"a", "42", "b"}) // Some(42)

func FindFirstMapWithIndex

func FindFirstMapWithIndex[A, B any](sel func(int, A) Option[B]) option.Kleisli[[]A, B]

FindFirstMapWithIndex finds the first element for which the selector function returns Some. The selector receives both the index and the element.

func FindFirstWithIndex

func FindFirstWithIndex[A any](pred func(int, A) bool) option.Kleisli[[]A, A]

FindFirstWithIndex finds the first element which satisfies a predicate function that also receives the index. Returns Some(element) if found, None if no element matches.

Example:

findEvenAtEvenIndex := array.FindFirstWithIndex(func(i, x int) bool {
    return i%2 == 0 && x%2 == 0
})
result := findEvenAtEvenIndex([]int{1, 3, 4, 5}) // Some(4)

func FindLast

func FindLast[A any](pred func(A) bool) option.Kleisli[[]A, A]

FindLast finds the last element which satisfies a predicate function. Returns Some(element) if found, None if no element matches.

Example:

findGreaterThan3 := array.FindLast(func(x int) bool { return x > 3 })
result := findGreaterThan3([]int{1, 4, 2, 5}) // Some(5)

func FindLastMap

func FindLastMap[A, B any](sel option.Kleisli[A, B]) option.Kleisli[[]A, B]

FindLastMap finds the last element for which the selector function returns Some. This combines finding and mapping in a single operation, searching from the end.

func FindLastMapWithIndex

func FindLastMapWithIndex[A, B any](sel func(int, A) Option[B]) option.Kleisli[[]A, B]

FindLastMapWithIndex finds the last element for which the selector function returns Some. The selector receives both the index and the element, searching from the end.

func FindLastWithIndex

func FindLastWithIndex[A any](pred func(int, A) bool) option.Kleisli[[]A, A]

FindLastWithIndex finds the last element which satisfies a predicate function that also receives the index. Returns Some(element) if found, None if no element matches.

func Flatten

func Flatten[A any](mma [][]A) []A

Flatten converts a nested array into a flat array by concatenating all inner arrays.

Example:

result := array.Flatten([][]int{{1, 2}, {3, 4}, {5}}) // [1, 2, 3, 4, 5]

func Fold

func Fold[A any](m M.Monoid[A]) func([]A) A

Fold folds the array using the provided Monoid.

func FoldMap

func FoldMap[A, B any](m M.Monoid[B]) func(func(A) B) func([]A) B

FoldMap maps and folds an array. Map the Array passing each value to the iterating function. Then fold the results using the provided Monoid.

Example
src := From("a", "b", "c")

fold := FoldMap[string](S.Monoid)(strings.ToUpper)

fmt.Println(fold(src))
Output:

ABC

func FoldMapWithIndex

func FoldMapWithIndex[A, B any](m M.Monoid[B]) func(func(int, A) B) func([]A) B

FoldMapWithIndex maps and folds an array. Map the Array passing each value to the iterating function. Then fold the results using the provided Monoid.

func From

func From[A any](data ...A) []A

From constructs an array from a set of variadic arguments

func Intercalate

func Intercalate[A any](m M.Monoid[A]) func(A) func([]A) A

Intercalate inserts a separator between elements and concatenates them using a Monoid.

func IsEmpty

func IsEmpty[A any](as []A) bool

IsEmpty checks if an array has no elements.

func IsNil

func IsNil[A any](as []A) bool

IsNil checks if the array is set to nil

func IsNonEmpty

func IsNonEmpty[A any](as []A) bool

IsNonEmpty checks if an array has at least one element.

func IsNonNil

func IsNonNil[A any](as []A) bool

IsNonNil checks if the array is set to nil

func Lookup

func Lookup[A any](idx int) func([]A) Option[A]

Lookup returns the element at the specified index, wrapped in an Option. Returns None if the index is out of bounds.

func MakeBy

func MakeBy[F ~func(int) A, A any](n int, f F) []A

MakeBy returns a `Array` of length `n` with element `i` initialized with `f(i)`.

func Match

func Match[A, B any](onEmpty func() B, onNonEmpty func([]A) B) func([]A) B

Match performs pattern matching on an array, calling onEmpty if empty or onNonEmpty if not.

func MatchLeft

func MatchLeft[A, B any](onEmpty func() B, onNonEmpty func(A, []A) B) func([]A) B

MatchLeft performs pattern matching on an array, calling onEmpty if empty or onNonEmpty with head and tail if not.

func Monad

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

Monad returns the monadic operations for an array. This provides a structured way to access all monad operations (Map, Chain, Ap, Of) for arrays in a single interface.

The Monad interface is useful when you need to pass monadic operations as parameters or when working with generic code that operates on any monad.

Example:

m := array.Monad[int, string]()
result := m.Chain([]int{1, 2, 3}, func(x int) []string {
    return []string{fmt.Sprintf("%d", x), fmt.Sprintf("%d!", x)}
})
// Result: ["1", "1!", "2", "2!", "3", "3!"]

func MonadAp

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

MonadAp applies an array of functions to an array of values, producing all combinations. This is the monadic version that takes both arrays as parameters.

func MonadChain

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

MonadChain applies a function that returns an array to each element and flattens the results. This is the monadic version that takes the array as the first parameter (also known as FlatMap).

func MonadFilterMap

func MonadFilterMap[A, B any](fa []A, f option.Kleisli[A, B]) []B

MonadFilterMap maps an array with a function that returns an Option and keeps only the Some values. This is the monadic version that takes the array as the first parameter.

func MonadFilterMapWithIndex

func MonadFilterMapWithIndex[A, B any](fa []A, f func(int, A) Option[B]) []B

MonadFilterMapWithIndex maps an array with a function that takes an index and returns an Option, keeping only the Some values. This is the monadic version that takes the array as the first parameter.

func MonadFlap

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

MonadFlap applies a value to an array of functions, producing an array of results. This is the monadic version that takes both parameters.

func MonadMap

func MonadMap[A, B any](as []A, f func(A) B) []B

MonadMap applies a function to each element of an array, returning a new array with the results. This is the monadic version of Map that takes the array as the first parameter.

func MonadMapRef

func MonadMapRef[A, B any](as []A, f func(*A) B) []B

MonadMapRef applies a function to a pointer to each element of an array, returning a new array with the results. This is useful when you need to access elements by reference without copying.

func MonadPartition

func MonadPartition[A any](as []A, pred func(A) bool) tuple.Tuple2[[]A, []A]

MonadPartition splits an array into two arrays based on a predicate. The first array contains elements for which the predicate returns false, the second contains elements for which it returns true.

func MonadReduce

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

func MonadSequence

func MonadSequence[HKTA, HKTRA any](
	fof func(HKTA) HKTRA,
	m M.Monoid[HKTRA],
	ma []HKTA) HKTRA

func MonadTraverse

func MonadTraverse[A, B, HKTB, HKTAB, HKTRB any](
	fof func([]B) HKTRB,
	fmap func(func([]B) func(B) []B) func(HKTRB) HKTAB,
	fap func(HKTB) func(HKTAB) HKTRB,

	ta []A,
	f func(A) HKTB) HKTRB

MonadTraverse is the monadic version of Traverse that takes the array as a parameter. It maps each element of an array to an effect (HKT), then collects the results into an effect of an array.

This is useful when you want to apply the traverse operation directly without currying.

func MonadTraverseWithIndex

func MonadTraverseWithIndex[A, B, HKTB, HKTAB, HKTRB any](
	fof func([]B) HKTRB,
	fmap func(func([]B) func(B) []B) func(HKTRB) HKTAB,
	fap func(HKTB) func(HKTAB) HKTRB,

	ta []A,
	f func(int, A) HKTB) HKTRB

func Monoid

func Monoid[T any]() M.Monoid[[]T]

Monoid returns a Monoid instance for arrays. The Monoid combines arrays through concatenation, with an empty array as the identity element.

Example:

m := array.Monoid[int]()
result := m.Concat([]int{1, 2}, []int{3, 4}) // [1, 2, 3, 4]
empty := m.Empty() // []

func Of

func Of[A any](a A) []A

Of constructs a single element array

func Partition

func Partition[A any](pred func(A) bool) func([]A) tuple.Tuple2[[]A, []A]

Partition creates two new arrays out of one, the left result contains the elements for which the predicate returns false, the right one those for which the predicate returns true

func Reduce

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

Reduce folds an array from left to right, applying a function to accumulate a result.

Example:

sum := array.Reduce(func(acc, x int) int { return acc + x }, 0)
result := sum([]int{1, 2, 3, 4, 5}) // 15

func ReduceRef

func ReduceRef[A, B any](f func(B, *A) B, initial B) func([]A) B

ReduceRef folds an array from left to right using pointers to elements, applying a function to accumulate a result.

func ReduceRight

func ReduceRight[A, B any](f func(A, B) B, initial B) func([]A) B

ReduceRight folds an array from right to left, applying a function to accumulate a result.

func ReduceRightWithIndex

func ReduceRightWithIndex[A, B any](f func(int, A, B) B, initial B) func([]A) B

ReduceRightWithIndex folds an array from right to left with access to the index, applying a function to accumulate a result.

func ReduceWithIndex

func ReduceWithIndex[A, B any](f func(int, B, A) B, initial B) func([]A) B

ReduceWithIndex folds an array from left to right with access to the index, applying a function to accumulate a result.

func Replicate

func Replicate[A any](n int, a A) []A

Replicate creates a `Array` containing a value repeated the specified number of times.

func Reverse

func Reverse[A any](as []A) []A

Reverse returns a new slice with elements in reverse order. This function creates a new slice containing all elements from the input slice in reverse order, without modifying the original slice.

Type Parameters:

  • A: The type of elements in the slice

Parameters:

  • as: The input slice to reverse

Returns:

  • A new slice with elements in reverse order

Behavior:

  • Creates a new slice with the same length as the input
  • Copies elements from the input slice in reverse order
  • Does not modify the original slice
  • Returns an empty slice if the input is empty
  • Returns a single-element slice unchanged if input has one element

Example:

numbers := []int{1, 2, 3, 4, 5}
reversed := array.Reverse(numbers)
// reversed: []int{5, 4, 3, 2, 1}
// numbers: []int{1, 2, 3, 4, 5} (unchanged)

Example with strings:

words := []string{"hello", "world", "foo", "bar"}
reversed := array.Reverse(words)
// reversed: []string{"bar", "foo", "world", "hello"}

Example with empty slice:

empty := []int{}
reversed := array.Reverse(empty)
// reversed: []int{} (empty slice)

Example with single element:

single := []string{"only"}
reversed := array.Reverse(single)
// reversed: []string{"only"}

Use cases:

  • Reversing the order of elements for display or processing
  • Implementing stack-like behavior (LIFO)
  • Processing data in reverse chronological order
  • Reversing transformation pipelines
  • Creating palindrome checks
  • Implementing undo/redo functionality

Example with processing in reverse:

events := []string{"start", "middle", "end"}
reversed := array.Reverse(events)
// Process events in reverse order
for _, event := range reversed {
    fmt.Println(event) // Prints: "end", "middle", "start"
}

Example with functional composition:

numbers := []int{1, 2, 3, 4, 5}
result := F.Pipe2(
    numbers,
    array.Map(N.Mul(2)),
    array.Reverse,
)
// result: []int{10, 8, 6, 4, 2}

Performance:

  • Time complexity: O(n) where n is the length of the slice
  • Space complexity: O(n) for the new slice
  • Does not allocate if the input slice is empty

Note: This function is immutable - it does not modify the original slice. If you need to reverse a slice in-place, consider using a different approach or modifying the slice directly.

func Semigroup

func Semigroup[T any]() S.Semigroup[[]T]

Semigroup returns a Semigroup instance for arrays. The Semigroup combines arrays through concatenation.

Example:

s := array.Semigroup[int]()
result := s.Concat([]int{1, 2}, []int{3, 4}) // [1, 2, 3, 4]

func Sequence

func Sequence[HKTA, HKTRA any](
	fof func(HKTA) HKTRA,
	m M.Monoid[HKTRA],
) func([]HKTA) HKTRA

Sequence takes an array where elements are HKT<A> (higher kinded type) and, using an applicative of that HKT, returns an HKT of []A.

For example, it can turn:

  • []Either[error, string] into Either[error, []string]
  • []Option[int] into Option[[]int]

Sequence requires an Applicative of the HKT you are targeting. To turn an []Either[E, A] into an Either[E, []A], it needs an Applicative for Either. To turn an []Option[A] into an Option[[]A], it needs an Applicative for Option.

Note: We need to pass the members of the applicative explicitly because Go does not support higher kinded types or template methods on structs or interfaces.

Type parameters:

  • HKTA = HKT<A> (e.g., Option[A], Either[E, A])
  • HKTRA = HKT<[]A> (e.g., Option[[]A], Either[E, []A])
  • HKTFRA = HKT<func(A)[]A> (e.g., Option[func(A)[]A])

Example:

import "github.com/IBM/fp-go/v2/option"

opts := []option.Option[int]{
    option.Some(1),
    option.Some(2),
    option.Some(3),
}

seq := array.Sequence(
    option.Of[[]int],
    option.MonadMap[[]int, func(int) []int],
    option.MonadAp[[]int, int],
)
result := seq(opts) // Some([1, 2, 3])

func Size

func Size[A any](as []A) int

Size returns the number of elements in an array.

func StrictUniq

func StrictUniq[A comparable](as []A) []A

StrictUniq converts an array of arbitrary items into an array of unique items where uniqueness is determined by the built-in equality constraint (comparable). The first occurrence of each unique value is kept, subsequent duplicates are removed.

Example:

numbers := []int{1, 2, 2, 3, 3, 3, 4}
unique := array.StrictUniq(numbers) // [1, 2, 3, 4]

strings := []string{"a", "b", "a", "c", "b"}
unique2 := array.StrictUniq(strings) // ["a", "b", "c"]

func Traverse

func Traverse[A, B, HKTB, HKTAB, HKTRB any](
	fof func([]B) HKTRB,
	fmap func(func([]B) func(B) []B) func(HKTRB) HKTAB,
	fap func(HKTB) func(HKTAB) HKTRB,

	f func(A) HKTB) func([]A) HKTRB

Traverse maps each element of an array to an effect (HKT), then collects the results into an effect of an array. This is like a combination of Map and Sequence.

Unlike Sequence which works with []HKT<A> -> HKT<[]A>, Traverse works with []A -> (A -> HKT<B>) -> HKT<[]B>, allowing you to transform elements while sequencing effects.

Type parameters:

  • HKTB = HKT<B> (e.g., Option[B], Either[E, B])
  • HKTAB = HKT<func(B)[]B> (intermediate type for applicative)
  • HKTRB = HKT<[]B> (e.g., Option[[]B], Either[E, []B])

Example:

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

// Parse strings to ints, returning None if any parse fails
parseAll := array.Traverse(
    option.Of[[]int],
    option.Map[[]int, func(int) []int],
    option.Ap[[]int, int],
    func(s string) option.Option[int] {
        if n, err := strconv.Atoi(s); err == nil {
            return option.Some(n)
        }
        return option.None[int]()
    },
)

result := parseAll([]string{"1", "2", "3"}) // Some([1, 2, 3])
result2 := parseAll([]string{"1", "x", "3"}) // None

func TraverseWithIndex

func TraverseWithIndex[A, B, HKTB, HKTAB, HKTRB any](
	fof func([]B) HKTRB,
	fmap func(func([]B) func(B) []B) func(HKTRB) HKTAB,
	fap func(HKTB) func(HKTAB) HKTRB,

	f func(int, A) HKTB) func([]A) HKTRB

func Unzip

func Unzip[A, B any](cs []T.Tuple2[A, B]) T.Tuple2[[]A, []B]

Unzip is the reverse of Zip. It takes an array of pairs (tuples) and returns two corresponding arrays, one containing all first elements and one containing all second elements.

Example:

import "github.com/IBM/fp-go/v2/tuple"

pairs := []tuple.Tuple2[string, int]{
    tuple.MakeTuple2("Alice", 30),
    tuple.MakeTuple2("Bob", 25),
    tuple.MakeTuple2("Charlie", 35),
}

result := array.Unzip(pairs)
// Result: (["Alice", "Bob", "Charlie"], [30, 25, 35])
names := result.Head  // ["Alice", "Bob", "Charlie"]
ages := result.Tail   // [30, 25, 35]

func Zero

func Zero[A any]() []A

Zero returns an empty array of type A (alias for Empty).

func Zip

func Zip[A, B any](fb []B) func([]A) []T.Tuple2[A, B]

Zip takes two arrays and returns an array of corresponding pairs (tuples). If one input array is shorter, excess elements of the longer array are discarded.

Example:

names := []string{"Alice", "Bob", "Charlie"}
ages := []int{30, 25, 35}

pairs := array.Zip(ages)(names)
// Result: [(Alice, 30), (Bob, 25), (Charlie, 35)]

// With different lengths
pairs2 := array.Zip([]int{1, 2})([]string{"a", "b", "c"})
// Result: [(a, 1), (b, 2)]

func ZipWith

func ZipWith[FCT ~func(A, B) C, A, B, C any](fa []A, fb []B, f FCT) []C

ZipWith applies a function to pairs of elements at the same index in two arrays, collecting the results in a new array. If one input array is shorter, excess elements of the longer array are discarded.

Example:

names := []string{"Alice", "Bob", "Charlie"}
ages := []int{30, 25, 35}

result := array.ZipWith(names, ages, func(name string, age int) string {
    return fmt.Sprintf("%s is %d years old", name, age)
})
// Result: ["Alice is 30 years old", "Bob is 25 years old", "Charlie is 35 years old"]

Types

type Kleisli

type Kleisli[A, B any] = func(A) []B

type Operator

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

func Ap

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

Ap applies an array of functions to an array of values, producing all combinations. This is the curried version.

func ApS

func ApS[S1, S2, T any](
	setter func(T) func(S1) S2,
	fa []T,
) Operator[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 semantics). This produces all combinations of context values and array values.

Example:

result := array.ApS(
    func(y int) func(s struct{ X int }) struct{ X, Y int } {
        return func(s struct{ X int }) struct{ X, Y int } {
            return struct{ X, Y int }{s.X, y}
        }
    },
    []int{10, 20},
)

func Bind

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

Bind attaches the result of a computation to a context S1 to produce a context S2. The setter function defines how to update the context with the computation result. This enables monadic composition where each step can produce multiple results.

Example:

result := F.Pipe2(
    array.Do(struct{ X, Y int }{}),
    array.Bind(
        func(x int) func(s struct{}) struct{ X int } {
            return func(s struct{}) struct{ X int } { return struct{ X int }{x} }
        },
        func(s struct{}) []int { return []int{1, 2} },
    ),
)

func BindTo

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

BindTo initializes a new state S1 from a value T. This is typically the first operation after Do to start building the context.

Example:

result := F.Pipe2(
    []int{1, 2, 3},
    array.BindTo(func(x int) struct{ X int } {
        return struct{ X int }{x}
    }),
)

func Chain

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

Chain applies a function that returns an array to each element and flattens the results. This is the curried version (also known as FlatMap).

Example:

duplicate := array.Chain(func(x int) []int { return []int{x, x} })
result := duplicate([]int{1, 2, 3}) // [1, 1, 2, 2, 3, 3]

func Clone

func Clone[A any](f func(A) A) Operator[A, A]

Clone creates a deep copy of the array using the provided endomorphism to clone the values

func Filter

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

Filter returns a new array with all elements from the original array that match a predicate

func FilterChain

func FilterChain[A, B any](f option.Kleisli[A, []B]) Operator[A, B]

FilterChain maps an array with an iterating function that returns an Option of an array. It keeps only the Some values discarding the Nones and then flattens the result.

func FilterMap

func FilterMap[A, B any](f option.Kleisli[A, B]) Operator[A, B]

FilterMap maps an array with an iterating function that returns an Option and it keeps only the Some values discarding the Nones.

func FilterMapRef

func FilterMapRef[A, B any](pred func(a *A) bool, f func(*A) B) Operator[A, B]

FilterMapRef filters an array using a predicate on pointers and maps the matching elements using a function on pointers.

func FilterMapWithIndex

func FilterMapWithIndex[A, B any](f func(int, A) Option[B]) Operator[A, B]

FilterMapWithIndex maps an array with an iterating function that returns an Option and it keeps only the Some values discarding the Nones.

func FilterRef

func FilterRef[A any](pred func(*A) bool) Operator[A, A]

FilterRef returns a new array with all elements from the original array that match a predicate operating on pointers.

func FilterWithIndex

func FilterWithIndex[A any](pred func(int, A) bool) Operator[A, A]

FilterWithIndex returns a new array with all elements from the original array that match a predicate

func Flap

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

Flap applies a value to an array of functions, producing an array of results. This is the curried version.

func Intersperse

func Intersperse[A any](middle A) Operator[A, A]

Intersperse inserts a separator between each element of an array.

Example:

result := array.Intersperse(0)([]int{1, 2, 3}) // [1, 0, 2, 0, 3]

func Let

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

Let attaches the result of a pure computation to a context S1 to produce a context S2. Unlike Bind, the computation function returns a plain value T rather than []T.

Example:

result := array.Let(
    func(sum int) func(s struct{ X int }) struct{ X, Sum int } {
        return func(s struct{ X int }) struct{ X, Sum int } {
            return struct{ X, Sum int }{s.X, sum}
        }
    },
    func(s struct{ X int }) int { return s.X * 2 },
)

func LetTo

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

LetTo attaches a constant value to a context S1 to produce a context S2. This is useful for adding constant values to the context.

Example:

result := array.LetTo(
    func(name string) func(s struct{ X int }) struct{ X int; Name string } {
        return func(s struct{ X int }) struct{ X int; Name string } {
            return struct{ X int; Name string }{s.X, name}
        }
    },
    "constant",
)

func Map

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

Map applies a function to each element of an array, returning a new array with the results. This is the curried version that returns a function.

Example:

double := array.Map(N.Mul(2))
result := double([]int{1, 2, 3}) // [2, 4, 6]

func MapRef

func MapRef[A, B any](f func(*A) B) Operator[A, B]

MapRef applies a function to a pointer to each element of an array, returning a new array with the results. This is the curried version that returns a function.

func MapWithIndex

func MapWithIndex[A, B any](f func(int, A) B) Operator[A, B]

MapWithIndex applies a function to each element and its index in an array, returning a new array with the results.

func Prepend

func Prepend[A any](head A) Operator[A, A]

Prepend adds an element to the beginning of an array, returning a new array.

func PrependAll

func PrependAll[A any](middle A) Operator[A, A]

PrependAll inserts a separator before each element of an array.

func Push

func Push[A any](a A) Operator[A, A]

Push adds an element to the end of an array (alias for Append).

func Slice

func Slice[A any](low, high int) Operator[A, A]

Slice extracts a subarray from index low (inclusive) to high (exclusive).

func SliceRight

func SliceRight[A any](start int) Operator[A, A]

SliceRight extracts a subarray from the specified start index to the end.

func Sort

func Sort[T any](ord O.Ord[T]) Operator[T, T]

Sort implements a stable sort on the array given the provided ordering. The sort is stable, meaning that elements that compare equal retain their original order.

Example:

import "github.com/IBM/fp-go/v2/ord"

numbers := []int{3, 1, 4, 1, 5, 9, 2, 6}
sorted := array.Sort(ord.FromStrictCompare[int]())(numbers)
// Result: [1, 1, 2, 3, 4, 5, 6, 9]

func SortBy

func SortBy[T any](ord []O.Ord[T]) Operator[T, T]

SortBy implements a stable sort on the array using multiple ordering criteria. The orderings are applied in sequence: if two elements are equal according to the first ordering, the second ordering is used, and so on.

Example:

import "github.com/IBM/fp-go/v2/ord"

type Person struct {
    LastName  string
    FirstName string
}

people := []Person{
    {"Smith", "John"},
    {"Smith", "Alice"},
    {"Jones", "Bob"},
}

sortByName := array.SortBy([]ord.Ord[Person]{
    ord.Contramap(func(p Person) string { return p.LastName })(ord.FromStrictCompare[string]()),
    ord.Contramap(func(p Person) string { return p.FirstName })(ord.FromStrictCompare[string]()),
})
sorted := sortByName(people)
// Result: [{"Jones", "Bob"}, {"Smith", "Alice"}, {"Smith", "John"}]

func SortByKey

func SortByKey[K, T any](ord O.Ord[K], f func(T) K) Operator[T, T]

SortByKey implements a stable sort on the array given the provided ordering on an extracted key. This is useful when you want to sort complex types by a specific field.

Example:

import "github.com/IBM/fp-go/v2/ord"

type Person struct {
    Name string
    Age  int
}

people := []Person{
    {"Alice", 30},
    {"Bob", 25},
    {"Charlie", 35},
}

sortByAge := array.SortByKey(
    ord.FromStrictCompare[int](),
    func(p Person) int { return p.Age },
)
sorted := sortByAge(people)
// Result: [{"Bob", 25}, {"Alice", 30}, {"Charlie", 35}]

func Uniq

func Uniq[A any, K comparable](f func(A) K) Operator[A, A]

Uniq converts an array of arbitrary items into an array of unique items where uniqueness is determined based on a key extractor function. The first occurrence of each unique key is kept, subsequent duplicates are removed.

This is useful for removing duplicates from arrays of complex types based on a specific field.

Example:

type Person struct {
    Name string
    Age  int
}

people := []Person{
    {"Alice", 30},
    {"Bob", 25},
    {"Alice", 35}, // duplicate name
    {"Charlie", 30},
}

uniqueByName := array.Uniq(func(p Person) string { return p.Name })
result := uniqueByName(people)
// Result: [{"Alice", 30}, {"Bob", 25}, {"Charlie", 30}]

func UpsertAt

func UpsertAt[A any](a A) Operator[A, A]

UpsertAt returns a function that inserts or updates an element at a specific index. If the index is out of bounds, the element is appended.

type Option

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

func ArrayOption

func ArrayOption[A any](ma []Option[A]) Option[[]A]

ArrayOption returns a function to convert a sequence of options into an option of a sequence. If all options are Some, returns Some containing an array of all values. If any option is None, returns None.

Example:

opts := []option.Option[int]{
    option.Some(1),
    option.Some(2),
    option.Some(3),
}
result := array.ArrayOption[int]()(opts) // Some([1, 2, 3])

opts2 := []option.Option[int]{
    option.Some(1),
    option.None[int](),
    option.Some(3),
}
result2 := array.ArrayOption[int]()(opts2) // None

func First

func First[A any](as []A) Option[A]

First returns the first element of an array, wrapped in an Option (alias for Head). Returns None if the array is empty.

func Head[A any](as []A) Option[A]

Head returns the first element of an array, wrapped in an Option. Returns None if the array is empty.

func Last

func Last[A any](as []A) Option[A]

Last returns the last element of an array, wrapped in an Option. Returns None if the array is empty.

func Tail

func Tail[A any](as []A) Option[[]A]

Tail returns all elements except the first, wrapped in an Option. Returns None if the array is empty.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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