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 ¶
- func Any[A any](pred func(A) bool) func([]A) bool
- func AnyWithIndex[A any](pred func(int, A) bool) func([]A) bool
- func Append[A any](as []A, a A) []A
- func ArrayConcatAll[A any](data ...[]A) []A
- func ConcatAll[A any](m M.Monoid[A]) func([]A) A
- func ConstNil[A any]() []A
- func Copy[A any](b []A) []A
- func Do[S any](empty S) []S
- func Empty[A any]() []A
- func Eq[T any](e E.Eq[T]) E.Eq[[]T]
- func FindFirst[A any](pred func(A) bool) option.Kleisli[[]A, A]
- func FindFirstMap[A, B any](sel option.Kleisli[A, B]) option.Kleisli[[]A, B]
- func FindFirstMapWithIndex[A, B any](sel func(int, A) Option[B]) option.Kleisli[[]A, B]
- func FindFirstWithIndex[A any](pred func(int, A) bool) option.Kleisli[[]A, A]
- func FindLast[A any](pred func(A) bool) option.Kleisli[[]A, A]
- func FindLastMap[A, B any](sel option.Kleisli[A, B]) option.Kleisli[[]A, B]
- func FindLastMapWithIndex[A, B any](sel func(int, A) Option[B]) option.Kleisli[[]A, B]
- func FindLastWithIndex[A any](pred func(int, A) bool) option.Kleisli[[]A, A]
- func Flatten[A any](mma [][]A) []A
- func Fold[A any](m M.Monoid[A]) func([]A) A
- func FoldMap[A, B any](m M.Monoid[B]) func(func(A) B) func([]A) B
- func FoldMapWithIndex[A, B any](m M.Monoid[B]) func(func(int, A) B) func([]A) B
- func From[A any](data ...A) []A
- func Intercalate[A any](m M.Monoid[A]) func(A) func([]A) A
- func IsEmpty[A any](as []A) bool
- func IsNil[A any](as []A) bool
- func IsNonEmpty[A any](as []A) bool
- func IsNonNil[A any](as []A) bool
- func Lookup[A any](idx int) func([]A) Option[A]
- func MakeBy[F ~func(int) A, A any](n int, f F) []A
- func Match[A, B any](onEmpty func() B, onNonEmpty func([]A) B) func([]A) B
- func MatchLeft[A, B any](onEmpty func() B, onNonEmpty func(A, []A) B) func([]A) B
- func Monad[A, B any]() monad.Monad[A, B, []A, []B, []func(A) B]
- func MonadAp[B, A any](fab []func(A) B, fa []A) []B
- func MonadChain[A, B any](fa []A, f Kleisli[A, B]) []B
- func MonadFilterMap[A, B any](fa []A, f option.Kleisli[A, B]) []B
- func MonadFilterMapWithIndex[A, B any](fa []A, f func(int, A) Option[B]) []B
- func MonadFlap[B, A any](fab []func(A) B, a A) []B
- func MonadMap[A, B any](as []A, f func(A) B) []B
- func MonadMapRef[A, B any](as []A, f func(*A) B) []B
- func MonadPartition[A any](as []A, pred func(A) bool) tuple.Tuple2[[]A, []A]
- func MonadReduce[A, B any](fa []A, f func(B, A) B, initial B) B
- func MonadSequence[HKTA, HKTRA any](fof func(HKTA) HKTRA, m M.Monoid[HKTRA], ma []HKTA) HKTRA
- func MonadTraverse[A, B, HKTB, HKTAB, HKTRB any](fof func([]B) HKTRB, fmap func(func([]B) func(B) []B) func(HKTRB) HKTAB, ...) HKTRB
- func MonadTraverseWithIndex[A, B, HKTB, HKTAB, HKTRB any](fof func([]B) HKTRB, fmap func(func([]B) func(B) []B) func(HKTRB) HKTAB, ...) HKTRB
- func Monoid[T any]() M.Monoid[[]T]
- func Of[A any](a A) []A
- func Partition[A any](pred func(A) bool) func([]A) tuple.Tuple2[[]A, []A]
- func Reduce[A, B any](f func(B, A) B, initial B) func([]A) B
- func ReduceRef[A, B any](f func(B, *A) B, initial B) func([]A) B
- func ReduceRight[A, B any](f func(A, B) B, initial B) func([]A) B
- func ReduceRightWithIndex[A, B any](f func(int, A, B) B, initial B) func([]A) B
- func ReduceWithIndex[A, B any](f func(int, B, A) B, initial B) func([]A) B
- func Replicate[A any](n int, a A) []A
- func Reverse[A any](as []A) []A
- func Semigroup[T any]() S.Semigroup[[]T]
- func Sequence[HKTA, HKTRA any](fof func(HKTA) HKTRA, m M.Monoid[HKTRA]) func([]HKTA) HKTRA
- func Size[A any](as []A) int
- func StrictUniq[A comparable](as []A) []A
- func Traverse[A, B, HKTB, HKTAB, HKTRB any](fof func([]B) HKTRB, fmap func(func([]B) func(B) []B) func(HKTRB) HKTAB, ...) func([]A) HKTRB
- func TraverseWithIndex[A, B, HKTB, HKTAB, HKTRB any](fof func([]B) HKTRB, fmap func(func([]B) func(B) []B) func(HKTRB) HKTAB, ...) func([]A) HKTRB
- func Unzip[A, B any](cs []T.Tuple2[A, B]) T.Tuple2[[]A, []B]
- func Zero[A any]() []A
- func Zip[A, B any](fb []B) func([]A) []T.Tuple2[A, B]
- func ZipWith[FCT ~func(A, B) C, A, B, C any](fa []A, fb []B, f FCT) []C
- type Kleisli
- type Operator
- func Ap[B, A any](fa []A) Operator[func(A) B, B]
- func ApS[S1, S2, T any](setter func(T) func(S1) S2, fa []T) Operator[S1, S2]
- func Bind[S1, S2, T any](setter func(T) func(S1) S2, f Kleisli[S1, T]) Operator[S1, S2]
- func BindTo[S1, T any](setter func(T) S1) Operator[T, S1]
- func Chain[A, B any](f Kleisli[A, B]) Operator[A, B]
- func Clone[A any](f func(A) A) Operator[A, A]
- func Filter[A any](pred func(A) bool) Operator[A, A]
- func FilterChain[A, B any](f option.Kleisli[A, []B]) Operator[A, B]
- func FilterMap[A, B any](f option.Kleisli[A, B]) Operator[A, B]
- func FilterMapRef[A, B any](pred func(a *A) bool, f func(*A) B) Operator[A, B]
- func FilterMapWithIndex[A, B any](f func(int, A) Option[B]) Operator[A, B]
- func FilterRef[A any](pred func(*A) bool) Operator[A, A]
- func FilterWithIndex[A any](pred func(int, A) bool) Operator[A, A]
- func Flap[B, A any](a A) Operator[func(A) B, B]
- func Intersperse[A any](middle A) Operator[A, A]
- func Let[S1, S2, T any](setter func(T) func(S1) S2, f func(S1) T) Operator[S1, S2]
- func LetTo[S1, S2, T any](setter func(T) func(S1) S2, b T) Operator[S1, S2]
- func Map[A, B any](f func(A) B) Operator[A, B]
- func MapRef[A, B any](f func(*A) B) Operator[A, B]
- func MapWithIndex[A, B any](f func(int, A) B) Operator[A, B]
- func Prepend[A any](head A) Operator[A, A]
- func PrependAll[A any](middle A) Operator[A, A]
- func Push[A any](a A) Operator[A, A]
- func Slice[A any](low, high int) Operator[A, A]
- func SliceRight[A any](start int) Operator[A, A]
- func Sort[T any](ord O.Ord[T]) Operator[T, T]
- func SortBy[T any](ord []O.Ord[T]) Operator[T, T]
- func SortByKey[K, T any](ord O.Ord[K], f func(T) K) Operator[T, T]
- func Uniq[A any, K comparable](f func(A) K) Operator[A, A]
- func UpsertAt[A any](a A) Operator[A, A]
- type Option
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Any ¶
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 ¶
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 ¶
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 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 Eq ¶
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 ¶
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 ¶
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 ¶
FindFirstMapWithIndex finds the first element for which the selector function returns Some. The selector receives both the index and the element.
func FindFirstWithIndex ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 FoldMap ¶
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 ¶
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 ¶
Intercalate inserts a separator between elements and concatenates them using a Monoid.
func IsNonEmpty ¶
IsNonEmpty checks if an array has at least one element.
func Lookup ¶
Lookup returns the element at the specified index, wrapped in an Option. Returns None if the index is out of bounds.
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 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 Monoid ¶
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 Partition ¶
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 ¶
ReduceRightWithIndex folds an array from right to left with access to the index, applying a function to accumulate a result.
func ReduceWithIndex ¶
ReduceWithIndex folds an array from left to right with access to the index, applying a function to accumulate a result.
func Replicate ¶
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 ¶
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 ¶
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 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 Unzip ¶
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 Zip ¶
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 Operator ¶
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 ¶
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 ¶
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 ¶
Filter returns a new array with all elements from the original array that match a predicate
func FilterChain ¶
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 ¶
FilterMap maps an array with an iterating function that returns an Option and it keeps only the Some values discarding the Nones.
func FilterMapRef ¶
FilterMapRef filters an array using a predicate on pointers and maps the matching elements using a function on pointers.
func FilterMapWithIndex ¶
FilterMapWithIndex maps an array with an iterating function that returns an Option and it keeps only the Some values discarding the Nones.
func FilterRef ¶
FilterRef returns a new array with all elements from the original array that match a predicate operating on pointers.
func FilterWithIndex ¶
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 ¶
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 SliceRight ¶
SliceRight extracts a subarray from the specified start index to the end.
func Sort ¶
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 ¶
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 ¶
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}]
type Option ¶
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 ¶
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.