mirror of
https://github.com/IBM/fp-go.git
synced 2025-11-23 22:14:53 +02:00
fix: support go iterators and cleanup types
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
@@ -17,11 +17,10 @@ package array
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
G "github.com/IBM/fp-go/v2/array/generic"
|
G "github.com/IBM/fp-go/v2/array/generic"
|
||||||
EM "github.com/IBM/fp-go/v2/endomorphism"
|
|
||||||
F "github.com/IBM/fp-go/v2/function"
|
F "github.com/IBM/fp-go/v2/function"
|
||||||
"github.com/IBM/fp-go/v2/internal/array"
|
"github.com/IBM/fp-go/v2/internal/array"
|
||||||
M "github.com/IBM/fp-go/v2/monoid"
|
M "github.com/IBM/fp-go/v2/monoid"
|
||||||
O "github.com/IBM/fp-go/v2/option"
|
"github.com/IBM/fp-go/v2/option"
|
||||||
"github.com/IBM/fp-go/v2/tuple"
|
"github.com/IBM/fp-go/v2/tuple"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -50,16 +49,16 @@ func Replicate[A any](n int, a A) []A {
|
|||||||
// This is the monadic version of Map that takes the array as the first parameter.
|
// This is the monadic version of Map that takes the array as the first parameter.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func MonadMap[A, B any](as []A, f func(a A) B) []B {
|
func MonadMap[A, B any](as []A, f func(A) B) []B {
|
||||||
return G.MonadMap[[]A, []B](as, f)
|
return G.MonadMap[[]A, []B](as, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MonadMapRef applies a function to a pointer to each element of an array, returning a new array with the results.
|
// 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.
|
// This is useful when you need to access elements by reference without copying.
|
||||||
func MonadMapRef[A, B any](as []A, f func(a *A) B) []B {
|
func MonadMapRef[A, B any](as []A, f func(*A) B) []B {
|
||||||
count := len(as)
|
count := len(as)
|
||||||
bs := make([]B, count)
|
bs := make([]B, count)
|
||||||
for i := count - 1; i >= 0; i-- {
|
for i := range count {
|
||||||
bs[i] = f(&as[i])
|
bs[i] = f(&as[i])
|
||||||
}
|
}
|
||||||
return bs
|
return bs
|
||||||
@@ -68,7 +67,7 @@ func MonadMapRef[A, B any](as []A, f func(a *A) B) []B {
|
|||||||
// MapWithIndex applies a function to each element and its index in an array, returning a new array with the results.
|
// MapWithIndex applies a function to each element and its index in an array, returning a new array with the results.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func MapWithIndex[A, B any](f func(int, A) B) func([]A) []B {
|
func MapWithIndex[A, B any](f func(int, A) B) Operator[A, B] {
|
||||||
return G.MapWithIndex[[]A, []B](f)
|
return G.MapWithIndex[[]A, []B](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,35 +80,35 @@ func MapWithIndex[A, B any](f func(int, A) B) func([]A) []B {
|
|||||||
// result := double([]int{1, 2, 3}) // [2, 4, 6]
|
// result := double([]int{1, 2, 3}) // [2, 4, 6]
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func Map[A, B any](f func(a A) B) func([]A) []B {
|
func Map[A, B any](f func(A) B) Operator[A, B] {
|
||||||
return G.Map[[]A, []B](f)
|
return G.Map[[]A, []B](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MapRef applies a function to a pointer to each element of an array, returning a new array with the results.
|
// 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.
|
// This is the curried version that returns a function.
|
||||||
func MapRef[A, B any](f func(a *A) B) func([]A) []B {
|
func MapRef[A, B any](f func(*A) B) Operator[A, B] {
|
||||||
return F.Bind2nd(MonadMapRef[A, B], f)
|
return F.Bind2nd(MonadMapRef[A, B], f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterRef[A any](fa []A, pred func(a *A) bool) []A {
|
func filterRef[A any](fa []A, pred func(*A) bool) []A {
|
||||||
var result []A
|
|
||||||
count := len(fa)
|
count := len(fa)
|
||||||
for i := 0; i < count; i++ {
|
var result []A = make([]A, 0, count)
|
||||||
a := fa[i]
|
for i := range count {
|
||||||
if pred(&a) {
|
a := &fa[i]
|
||||||
result = append(result, a)
|
if pred(a) {
|
||||||
|
result = append(result, *a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterMapRef[A, B any](fa []A, pred func(a *A) bool, f func(a *A) B) []B {
|
func filterMapRef[A, B any](fa []A, pred func(*A) bool, f func(*A) B) []B {
|
||||||
var result []B
|
|
||||||
count := len(fa)
|
count := len(fa)
|
||||||
for i := 0; i < count; i++ {
|
var result []B = make([]B, 0, count)
|
||||||
a := fa[i]
|
for i := range count {
|
||||||
if pred(&a) {
|
a := &fa[i]
|
||||||
result = append(result, f(&a))
|
if pred(a) {
|
||||||
|
result = append(result, f(a))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
@@ -118,19 +117,19 @@ func filterMapRef[A, B any](fa []A, pred func(a *A) bool, f func(a *A) B) []B {
|
|||||||
// Filter returns a new array with all elements from the original array that match a predicate
|
// Filter returns a new array with all elements from the original array that match a predicate
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func Filter[A any](pred func(A) bool) EM.Endomorphism[[]A] {
|
func Filter[A any](pred func(A) bool) Operator[A, A] {
|
||||||
return G.Filter[[]A](pred)
|
return G.Filter[[]A](pred)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterWithIndex returns a new array with all elements from the original array that match a predicate
|
// FilterWithIndex returns a new array with all elements from the original array that match a predicate
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func FilterWithIndex[A any](pred func(int, A) bool) EM.Endomorphism[[]A] {
|
func FilterWithIndex[A any](pred func(int, A) bool) Operator[A, A] {
|
||||||
return G.FilterWithIndex[[]A](pred)
|
return G.FilterWithIndex[[]A](pred)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterRef returns a new array with all elements from the original array that match a predicate operating on pointers.
|
// FilterRef returns a new array with all elements from the original array that match a predicate operating on pointers.
|
||||||
func FilterRef[A any](pred func(*A) bool) EM.Endomorphism[[]A] {
|
func FilterRef[A any](pred func(*A) bool) Operator[A, A] {
|
||||||
return F.Bind2nd(filterRef[A], pred)
|
return F.Bind2nd(filterRef[A], pred)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +137,7 @@ func FilterRef[A any](pred func(*A) bool) EM.Endomorphism[[]A] {
|
|||||||
// This is the monadic version that takes the array as the first parameter.
|
// This is the monadic version that takes the array as the first parameter.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func MonadFilterMap[A, B any](fa []A, f func(A) O.Option[B]) []B {
|
func MonadFilterMap[A, B any](fa []A, f option.Kleisli[A, B]) []B {
|
||||||
return G.MonadFilterMap[[]A, []B](fa, f)
|
return G.MonadFilterMap[[]A, []B](fa, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,33 +145,33 @@ func MonadFilterMap[A, B any](fa []A, f func(A) O.Option[B]) []B {
|
|||||||
// keeping only the Some values. This is the monadic version that takes the array as the first parameter.
|
// keeping only the Some values. This is the monadic version that takes the array as the first parameter.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func MonadFilterMapWithIndex[A, B any](fa []A, f func(int, A) O.Option[B]) []B {
|
func MonadFilterMapWithIndex[A, B any](fa []A, f func(int, A) Option[B]) []B {
|
||||||
return G.MonadFilterMapWithIndex[[]A, []B](fa, f)
|
return G.MonadFilterMapWithIndex[[]A, []B](fa, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterMap maps an array with an iterating function that returns an [O.Option] and it keeps only the Some values discarding the Nones.
|
// FilterMap maps an array with an iterating function that returns an [Option] and it keeps only the Some values discarding the Nones.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func FilterMap[A, B any](f func(A) O.Option[B]) func([]A) []B {
|
func FilterMap[A, B any](f option.Kleisli[A, B]) Operator[A, B] {
|
||||||
return G.FilterMap[[]A, []B](f)
|
return G.FilterMap[[]A, []B](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterMapWithIndex maps an array with an iterating function that returns an [O.Option] and it keeps only the Some values discarding the Nones.
|
// FilterMapWithIndex maps an array with an iterating function that returns an [Option] and it keeps only the Some values discarding the Nones.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func FilterMapWithIndex[A, B any](f func(int, A) O.Option[B]) func([]A) []B {
|
func FilterMapWithIndex[A, B any](f func(int, A) Option[B]) Operator[A, B] {
|
||||||
return G.FilterMapWithIndex[[]A, []B](f)
|
return G.FilterMapWithIndex[[]A, []B](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterChain maps an array with an iterating function that returns an [O.Option] of an array. It keeps only the Some values discarding the Nones and then flattens the result.
|
// 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.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func FilterChain[A, B any](f func(A) O.Option[[]B]) func([]A) []B {
|
func FilterChain[A, B any](f option.Kleisli[A, []B]) Operator[A, B] {
|
||||||
return G.FilterChain[[]A](f)
|
return G.FilterChain[[]A](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterMapRef filters an array using a predicate on pointers and maps the matching elements using a function on pointers.
|
// FilterMapRef filters an array using a predicate on pointers and maps the matching elements using a function on pointers.
|
||||||
func FilterMapRef[A, B any](pred func(a *A) bool, f func(a *A) B) func([]A) []B {
|
func FilterMapRef[A, B any](pred func(a *A) bool, f func(*A) B) Operator[A, B] {
|
||||||
return func(fa []A) []B {
|
return func(fa []A) []B {
|
||||||
return filterMapRef(fa, pred, f)
|
return filterMapRef(fa, pred, f)
|
||||||
}
|
}
|
||||||
@@ -180,8 +179,7 @@ func FilterMapRef[A, B any](pred func(a *A) bool, f func(a *A) B) func([]A) []B
|
|||||||
|
|
||||||
func reduceRef[A, B any](fa []A, f func(B, *A) B, initial B) B {
|
func reduceRef[A, B any](fa []A, f func(B, *A) B, initial B) B {
|
||||||
current := initial
|
current := initial
|
||||||
count := len(fa)
|
for i := range len(fa) {
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
current = f(current, &fa[i])
|
current = f(current, &fa[i])
|
||||||
}
|
}
|
||||||
return current
|
return current
|
||||||
@@ -277,7 +275,7 @@ func Of[A any](a A) []A {
|
|||||||
// This is the monadic version that takes the array as the first parameter (also known as FlatMap).
|
// This is the monadic version that takes the array as the first parameter (also known as FlatMap).
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func MonadChain[A, B any](fa []A, f func(a A) []B) []B {
|
func MonadChain[A, B any](fa []A, f Kleisli[A, B]) []B {
|
||||||
return G.MonadChain(fa, f)
|
return G.MonadChain(fa, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,7 +288,7 @@ func MonadChain[A, B any](fa []A, f func(a A) []B) []B {
|
|||||||
// result := duplicate([]int{1, 2, 3}) // [1, 1, 2, 2, 3, 3]
|
// result := duplicate([]int{1, 2, 3}) // [1, 1, 2, 2, 3, 3]
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func Chain[A, B any](f func(A) []B) func([]A) []B {
|
func Chain[A, B any](f Kleisli[A, B]) Operator[A, B] {
|
||||||
return G.Chain[[]A](f)
|
return G.Chain[[]A](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,7 +304,7 @@ func MonadAp[B, A any](fab []func(A) B, fa []A) []B {
|
|||||||
// This is the curried version.
|
// This is the curried version.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func Ap[B, A any](fa []A) func([]func(A) B) []B {
|
func Ap[B, A any](fa []A) Operator[func(A) B, B] {
|
||||||
return G.Ap[[]B, []func(A) B](fa)
|
return G.Ap[[]B, []func(A) B](fa)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,7 +326,7 @@ func MatchLeft[A, B any](onEmpty func() B, onNonEmpty func(A, []A) B) func([]A)
|
|||||||
// Returns None if the array is empty.
|
// Returns None if the array is empty.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func Tail[A any](as []A) O.Option[[]A] {
|
func Tail[A any](as []A) Option[[]A] {
|
||||||
return G.Tail(as)
|
return G.Tail(as)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,7 +334,7 @@ func Tail[A any](as []A) O.Option[[]A] {
|
|||||||
// Returns None if the array is empty.
|
// Returns None if the array is empty.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func Head[A any](as []A) O.Option[A] {
|
func Head[A any](as []A) Option[A] {
|
||||||
return G.Head(as)
|
return G.Head(as)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,7 +342,7 @@ func Head[A any](as []A) O.Option[A] {
|
|||||||
// Returns None if the array is empty.
|
// Returns None if the array is empty.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func First[A any](as []A) O.Option[A] {
|
func First[A any](as []A) Option[A] {
|
||||||
return G.First(as)
|
return G.First(as)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,12 +350,12 @@ func First[A any](as []A) O.Option[A] {
|
|||||||
// Returns None if the array is empty.
|
// Returns None if the array is empty.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func Last[A any](as []A) O.Option[A] {
|
func Last[A any](as []A) Option[A] {
|
||||||
return G.Last(as)
|
return G.Last(as)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrependAll inserts a separator before each element of an array.
|
// PrependAll inserts a separator before each element of an array.
|
||||||
func PrependAll[A any](middle A) EM.Endomorphism[[]A] {
|
func PrependAll[A any](middle A) Operator[A, A] {
|
||||||
return func(as []A) []A {
|
return func(as []A) []A {
|
||||||
count := len(as)
|
count := len(as)
|
||||||
dst := count * 2
|
dst := count * 2
|
||||||
@@ -377,7 +375,7 @@ func PrependAll[A any](middle A) EM.Endomorphism[[]A] {
|
|||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// result := array.Intersperse(0)([]int{1, 2, 3}) // [1, 0, 2, 0, 3]
|
// result := array.Intersperse(0)([]int{1, 2, 3}) // [1, 0, 2, 0, 3]
|
||||||
func Intersperse[A any](middle A) EM.Endomorphism[[]A] {
|
func Intersperse[A any](middle A) Operator[A, A] {
|
||||||
prepend := PrependAll(middle)
|
prepend := PrependAll(middle)
|
||||||
return func(as []A) []A {
|
return func(as []A) []A {
|
||||||
if IsEmpty(as) {
|
if IsEmpty(as) {
|
||||||
@@ -406,7 +404,7 @@ func Flatten[A any](mma [][]A) []A {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Slice extracts a subarray from index low (inclusive) to high (exclusive).
|
// Slice extracts a subarray from index low (inclusive) to high (exclusive).
|
||||||
func Slice[A any](low, high int) func(as []A) []A {
|
func Slice[A any](low, high int) Operator[A, A] {
|
||||||
return array.Slice[[]A](low, high)
|
return array.Slice[[]A](low, high)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,7 +412,7 @@ func Slice[A any](low, high int) func(as []A) []A {
|
|||||||
// Returns None if the index is out of bounds.
|
// Returns None if the index is out of bounds.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func Lookup[A any](idx int) func([]A) O.Option[A] {
|
func Lookup[A any](idx int) func([]A) Option[A] {
|
||||||
return G.Lookup[[]A](idx)
|
return G.Lookup[[]A](idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,7 +420,7 @@ func Lookup[A any](idx int) func([]A) O.Option[A] {
|
|||||||
// If the index is out of bounds, the element is appended.
|
// If the index is out of bounds, the element is appended.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func UpsertAt[A any](a A) EM.Endomorphism[[]A] {
|
func UpsertAt[A any](a A) Operator[A, A] {
|
||||||
return G.UpsertAt[[]A](a)
|
return G.UpsertAt[[]A](a)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,7 +466,7 @@ func ConstNil[A any]() []A {
|
|||||||
// SliceRight extracts a subarray from the specified start index to the end.
|
// SliceRight extracts a subarray from the specified start index to the end.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func SliceRight[A any](start int) EM.Endomorphism[[]A] {
|
func SliceRight[A any](start int) Operator[A, A] {
|
||||||
return G.SliceRight[[]A](start)
|
return G.SliceRight[[]A](start)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,7 +480,7 @@ func Copy[A any](b []A) []A {
|
|||||||
// Clone creates a deep copy of the array using the provided endomorphism to clone the values
|
// Clone creates a deep copy of the array using the provided endomorphism to clone the values
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func Clone[A any](f func(A) A) func(as []A) []A {
|
func Clone[A any](f func(A) A) Operator[A, A] {
|
||||||
return G.Clone[[]A](f)
|
return G.Clone[[]A](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,8 +508,8 @@ func Fold[A any](m M.Monoid[A]) func([]A) A {
|
|||||||
// Push adds an element to the end of an array (alias for Append).
|
// Push adds an element to the end of an array (alias for Append).
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func Push[A any](a A) EM.Endomorphism[[]A] {
|
func Push[A any](a A) Operator[A, A] {
|
||||||
return G.Push[EM.Endomorphism[[]A]](a)
|
return G.Push[Operator[A, A]](a)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MonadFlap applies a value to an array of functions, producing an array of results.
|
// MonadFlap applies a value to an array of functions, producing an array of results.
|
||||||
@@ -526,13 +524,13 @@ func MonadFlap[B, A any](fab []func(A) B, a A) []B {
|
|||||||
// This is the curried version.
|
// This is the curried version.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func Flap[B, A any](a A) func([]func(A) B) []B {
|
func Flap[B, A any](a A) Operator[func(A) B, B] {
|
||||||
return G.Flap[func(A) B, []func(A) B, []B](a)
|
return G.Flap[func(A) B, []func(A) B, []B](a)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepend adds an element to the beginning of an array, returning a new array.
|
// Prepend adds an element to the beginning of an array, returning a new array.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func Prepend[A any](head A) EM.Endomorphism[[]A] {
|
func Prepend[A any](head A) Operator[A, A] {
|
||||||
return G.Prepend[EM.Endomorphism[[]A]](head)
|
return G.Prepend[Operator[A, A]](head)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ func Do[S any](
|
|||||||
//go:inline
|
//go:inline
|
||||||
func Bind[S1, S2, T any](
|
func Bind[S1, S2, T any](
|
||||||
setter func(T) func(S1) S2,
|
setter func(T) func(S1) S2,
|
||||||
f func(S1) []T,
|
f Kleisli[S1, T],
|
||||||
) func([]S1) []S2 {
|
) Operator[S1, S2] {
|
||||||
return G.Bind[[]S1, []S2](setter, f)
|
return G.Bind[[]S1, []S2](setter, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ func Bind[S1, S2, T any](
|
|||||||
func Let[S1, S2, T any](
|
func Let[S1, S2, T any](
|
||||||
setter func(T) func(S1) S2,
|
setter func(T) func(S1) S2,
|
||||||
f func(S1) T,
|
f func(S1) T,
|
||||||
) func([]S1) []S2 {
|
) Operator[S1, S2] {
|
||||||
return G.Let[[]S1, []S2](setter, f)
|
return G.Let[[]S1, []S2](setter, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ func Let[S1, S2, T any](
|
|||||||
func LetTo[S1, S2, T any](
|
func LetTo[S1, S2, T any](
|
||||||
setter func(T) func(S1) S2,
|
setter func(T) func(S1) S2,
|
||||||
b T,
|
b T,
|
||||||
) func([]S1) []S2 {
|
) Operator[S1, S2] {
|
||||||
return G.LetTo[[]S1, []S2](setter, b)
|
return G.LetTo[[]S1, []S2](setter, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ func LetTo[S1, S2, T any](
|
|||||||
//go:inline
|
//go:inline
|
||||||
func BindTo[S1, T any](
|
func BindTo[S1, T any](
|
||||||
setter func(T) S1,
|
setter func(T) S1,
|
||||||
) func([]T) []S1 {
|
) Operator[T, S1] {
|
||||||
return G.BindTo[[]S1, []T](setter)
|
return G.BindTo[[]S1, []T](setter)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +143,6 @@ func BindTo[S1, T any](
|
|||||||
func ApS[S1, S2, T any](
|
func ApS[S1, S2, T any](
|
||||||
setter func(T) func(S1) S2,
|
setter func(T) func(S1) S2,
|
||||||
fa []T,
|
fa []T,
|
||||||
) func([]S1) []S2 {
|
) Operator[S1, S2] {
|
||||||
return G.ApS[[]S1, []S2](setter, fa)
|
return G.ApS[[]S1, []S2](setter, fa)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ package array
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
G "github.com/IBM/fp-go/v2/array/generic"
|
G "github.com/IBM/fp-go/v2/array/generic"
|
||||||
O "github.com/IBM/fp-go/v2/option"
|
"github.com/IBM/fp-go/v2/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FindFirst finds the first element which satisfies a predicate function.
|
// FindFirst finds the first element which satisfies a predicate function.
|
||||||
@@ -30,7 +30,7 @@ import (
|
|||||||
// result2 := findGreaterThan3([]int{1, 2, 3}) // None
|
// result2 := findGreaterThan3([]int{1, 2, 3}) // None
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func FindFirst[A any](pred func(A) bool) func([]A) O.Option[A] {
|
func FindFirst[A any](pred func(A) bool) option.Kleisli[[]A, A] {
|
||||||
return G.FindFirst[[]A](pred)
|
return G.FindFirst[[]A](pred)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ func FindFirst[A any](pred func(A) bool) func([]A) O.Option[A] {
|
|||||||
// result := findEvenAtEvenIndex([]int{1, 3, 4, 5}) // Some(4)
|
// result := findEvenAtEvenIndex([]int{1, 3, 4, 5}) // Some(4)
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func FindFirstWithIndex[A any](pred func(int, A) bool) func([]A) O.Option[A] {
|
func FindFirstWithIndex[A any](pred func(int, A) bool) option.Kleisli[[]A, A] {
|
||||||
return G.FindFirstWithIndex[[]A](pred)
|
return G.FindFirstWithIndex[[]A](pred)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ func FindFirstWithIndex[A any](pred func(int, A) bool) func([]A) O.Option[A] {
|
|||||||
// result := parseFirst([]string{"a", "42", "b"}) // Some(42)
|
// result := parseFirst([]string{"a", "42", "b"}) // Some(42)
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func FindFirstMap[A, B any](sel func(A) O.Option[B]) func([]A) O.Option[B] {
|
func FindFirstMap[A, B any](sel option.Kleisli[A, B]) option.Kleisli[[]A, B] {
|
||||||
return G.FindFirstMap[[]A](sel)
|
return G.FindFirstMap[[]A](sel)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ func FindFirstMap[A, B any](sel func(A) O.Option[B]) func([]A) O.Option[B] {
|
|||||||
// The selector receives both the index and the element.
|
// The selector receives both the index and the element.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func FindFirstMapWithIndex[A, B any](sel func(int, A) O.Option[B]) func([]A) O.Option[B] {
|
func FindFirstMapWithIndex[A, B any](sel func(int, A) Option[B]) option.Kleisli[[]A, B] {
|
||||||
return G.FindFirstMapWithIndex[[]A](sel)
|
return G.FindFirstMapWithIndex[[]A](sel)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ func FindFirstMapWithIndex[A, B any](sel func(int, A) O.Option[B]) func([]A) O.O
|
|||||||
// result := findGreaterThan3([]int{1, 4, 2, 5}) // Some(5)
|
// result := findGreaterThan3([]int{1, 4, 2, 5}) // Some(5)
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func FindLast[A any](pred func(A) bool) func([]A) O.Option[A] {
|
func FindLast[A any](pred func(A) bool) option.Kleisli[[]A, A] {
|
||||||
return G.FindLast[[]A](pred)
|
return G.FindLast[[]A](pred)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ func FindLast[A any](pred func(A) bool) func([]A) O.Option[A] {
|
|||||||
// Returns Some(element) if found, None if no element matches.
|
// Returns Some(element) if found, None if no element matches.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func FindLastWithIndex[A any](pred func(int, A) bool) func([]A) O.Option[A] {
|
func FindLastWithIndex[A any](pred func(int, A) bool) option.Kleisli[[]A, A] {
|
||||||
return G.FindLastWithIndex[[]A](pred)
|
return G.FindLastWithIndex[[]A](pred)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ func FindLastWithIndex[A any](pred func(int, A) bool) func([]A) O.Option[A] {
|
|||||||
// This combines finding and mapping in a single operation, searching from the end.
|
// This combines finding and mapping in a single operation, searching from the end.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func FindLastMap[A, B any](sel func(A) O.Option[B]) func([]A) O.Option[B] {
|
func FindLastMap[A, B any](sel option.Kleisli[A, B]) option.Kleisli[[]A, B] {
|
||||||
return G.FindLastMap[[]A](sel)
|
return G.FindLastMap[[]A](sel)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +110,6 @@ func FindLastMap[A, B any](sel func(A) O.Option[B]) func([]A) O.Option[B] {
|
|||||||
// The selector receives both the index and the element, searching from the end.
|
// The selector receives both the index and the element, searching from the end.
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func FindLastMapWithIndex[A, B any](sel func(int, A) O.Option[B]) func([]A) O.Option[B] {
|
func FindLastMapWithIndex[A, B any](sel func(int, A) Option[B]) option.Kleisli[[]A, B] {
|
||||||
return G.FindLastMapWithIndex[[]A](sel)
|
return G.FindLastMapWithIndex[[]A](sel)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ func MakeBy[AS ~[]A, F ~func(int) A, A any](n int, f F) AS {
|
|||||||
}
|
}
|
||||||
// run the generator function across the input
|
// run the generator function across the input
|
||||||
as := make(AS, n)
|
as := make(AS, n)
|
||||||
for i := n - 1; i >= 0; i-- {
|
for i := range n {
|
||||||
as[i] = f(i)
|
as[i] = f(i)
|
||||||
}
|
}
|
||||||
return as
|
return as
|
||||||
@@ -165,10 +165,9 @@ func Size[GA ~[]A, A any](as GA) int {
|
|||||||
func filterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(A) O.Option[B]) GB {
|
func filterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(A) O.Option[B]) GB {
|
||||||
result := make(GB, 0, len(fa))
|
result := make(GB, 0, len(fa))
|
||||||
for _, a := range fa {
|
for _, a := range fa {
|
||||||
O.Map(func(b B) B {
|
if b, ok := O.Unwrap(f(a)); ok {
|
||||||
result = append(result, b)
|
result = append(result, b)
|
||||||
return b
|
}
|
||||||
})(f(a))
|
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -176,10 +175,9 @@ func filterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(A) O.Option[B]) GB {
|
|||||||
func filterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(int, A) O.Option[B]) GB {
|
func filterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(int, A) O.Option[B]) GB {
|
||||||
result := make(GB, 0, len(fa))
|
result := make(GB, 0, len(fa))
|
||||||
for i, a := range fa {
|
for i, a := range fa {
|
||||||
O.Map(func(b B) B {
|
if b, ok := O.Unwrap(f(i, a)); ok {
|
||||||
result = append(result, b)
|
result = append(result, b)
|
||||||
return b
|
}
|
||||||
})(f(i, a))
|
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,8 +42,7 @@ func FindFirst[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) O.Option[
|
|||||||
func FindFirstMapWithIndex[AS ~[]A, PRED ~func(int, A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
func FindFirstMapWithIndex[AS ~[]A, PRED ~func(int, A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
||||||
none := O.None[B]()
|
none := O.None[B]()
|
||||||
return func(as AS) O.Option[B] {
|
return func(as AS) O.Option[B] {
|
||||||
count := len(as)
|
for i := range len(as) {
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
out := pred(i, as[i])
|
out := pred(i, as[i])
|
||||||
if O.IsSome(out) {
|
if O.IsSome(out) {
|
||||||
return out
|
return out
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import (
|
|||||||
func ZipWith[AS ~[]A, BS ~[]B, CS ~[]C, FCT ~func(A, B) C, A, B, C any](fa AS, fb BS, f FCT) CS {
|
func ZipWith[AS ~[]A, BS ~[]B, CS ~[]C, FCT ~func(A, B) C, A, B, C any](fa AS, fb BS, f FCT) CS {
|
||||||
l := N.Min(len(fa), len(fb))
|
l := N.Min(len(fa), len(fb))
|
||||||
res := make(CS, l)
|
res := make(CS, l)
|
||||||
for i := l - 1; i >= 0; i-- {
|
for i := range l {
|
||||||
res[i] = f(fa[i], fb[i])
|
res[i] = f(fa[i], fb[i])
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
@@ -43,7 +43,7 @@ func Unzip[AS ~[]A, BS ~[]B, CS ~[]T.Tuple2[A, B], A, B any](cs CS) T.Tuple2[AS,
|
|||||||
l := len(cs)
|
l := len(cs)
|
||||||
as := make(AS, l)
|
as := make(AS, l)
|
||||||
bs := make(BS, l)
|
bs := make(BS, l)
|
||||||
for i := l - 1; i >= 0; i-- {
|
for i := range l {
|
||||||
t := cs[i]
|
t := cs[i]
|
||||||
as[i] = t.F1
|
as[i] = t.F1
|
||||||
bs[i] = t.F2
|
bs[i] = t.F2
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ func Sequence[A, HKTA, HKTRA, HKTFRA any](
|
|||||||
// option.Some(3),
|
// option.Some(3),
|
||||||
// }
|
// }
|
||||||
// result2 := array.ArrayOption[int]()(opts2) // None
|
// result2 := array.ArrayOption[int]()(opts2) // None
|
||||||
func ArrayOption[A any]() func([]O.Option[A]) O.Option[[]A] {
|
func ArrayOption[A any]() func([]Option[A]) Option[[]A] {
|
||||||
return Sequence(
|
return Sequence(
|
||||||
O.Of[[]A],
|
O.Of[[]A],
|
||||||
O.MonadMap[[]A, func(A) []A],
|
O.MonadMap[[]A, func(A) []A],
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import (
|
|||||||
// // Result: [1, 1, 2, 3, 4, 5, 6, 9]
|
// // Result: [1, 1, 2, 3, 4, 5, 6, 9]
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func Sort[T any](ord O.Ord[T]) func(ma []T) []T {
|
func Sort[T any](ord O.Ord[T]) Operator[T, T] {
|
||||||
return G.Sort[[]T](ord)
|
return G.Sort[[]T](ord)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ func Sort[T any](ord O.Ord[T]) func(ma []T) []T {
|
|||||||
// // Result: [{"Bob", 25}, {"Alice", 30}, {"Charlie", 35}]
|
// // Result: [{"Bob", 25}, {"Alice", 30}, {"Charlie", 35}]
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func SortByKey[K, T any](ord O.Ord[K], f func(T) K) func(ma []T) []T {
|
func SortByKey[K, T any](ord O.Ord[K], f func(T) K) Operator[T, T] {
|
||||||
return G.SortByKey[[]T](ord, f)
|
return G.SortByKey[[]T](ord, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +93,6 @@ func SortByKey[K, T any](ord O.Ord[K], f func(T) K) func(ma []T) []T {
|
|||||||
// // Result: [{"Jones", "Bob"}, {"Smith", "Alice"}, {"Smith", "John"}]
|
// // Result: [{"Jones", "Bob"}, {"Smith", "Alice"}, {"Smith", "John"}]
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func SortBy[T any](ord []O.Ord[T]) func(ma []T) []T {
|
func SortBy[T any](ord []O.Ord[T]) Operator[T, T] {
|
||||||
return G.SortBy[[]T](ord)
|
return G.SortBy[[]T](ord)
|
||||||
}
|
}
|
||||||
|
|||||||
9
v2/array/types.go
Normal file
9
v2/array/types.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package array
|
||||||
|
|
||||||
|
import "github.com/IBM/fp-go/v2/option"
|
||||||
|
|
||||||
|
type (
|
||||||
|
Kleisli[A, B any] = func(A) []B
|
||||||
|
Operator[A, B any] = Kleisli[[]A, B]
|
||||||
|
Option[A any] = option.Option[A]
|
||||||
|
)
|
||||||
@@ -46,6 +46,6 @@ func StrictUniq[A comparable](as []A) []A {
|
|||||||
// // Result: [{"Alice", 30}, {"Bob", 25}, {"Charlie", 30}]
|
// // Result: [{"Alice", 30}, {"Bob", 25}, {"Charlie", 30}]
|
||||||
//
|
//
|
||||||
//go:inline
|
//go:inline
|
||||||
func Uniq[A any, K comparable](f func(A) K) func(as []A) []A {
|
func Uniq[A any, K comparable](f func(A) K) Operator[A, A] {
|
||||||
return G.Uniq[[]A](f)
|
return G.Uniq[[]A](f)
|
||||||
}
|
}
|
||||||
|
|||||||
11
v2/constant/monoid.go
Normal file
11
v2/constant/monoid.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package constant
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/IBM/fp-go/v2/function"
|
||||||
|
M "github.com/IBM/fp-go/v2/monoid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Monoid returns a [M.Monoid] that returns a constant value in all operations
|
||||||
|
func Monoid[A any](a A) M.Monoid[A] {
|
||||||
|
return M.MakeMonoid(function.Constant2[A, A](a), a)
|
||||||
|
}
|
||||||
10
v2/endomorphism/from.go
Normal file
10
v2/endomorphism/from.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package endomorphism
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/IBM/fp-go/v2/function"
|
||||||
|
S "github.com/IBM/fp-go/v2/semigroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FromSemigroup[A any](s S.Semigroup[A]) Kleisli[A] {
|
||||||
|
return function.Bind2of2(s.Concat)
|
||||||
|
}
|
||||||
892
v2/iterator/iter/iter.go
Normal file
892
v2/iterator/iter/iter.go
Normal file
@@ -0,0 +1,892 @@
|
|||||||
|
// Copyright (c) 2023 - 2025 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package iter provides functional programming utilities for Go 1.23+ iterators.
|
||||||
|
//
|
||||||
|
// This package offers a comprehensive set of operations for working with lazy sequences
|
||||||
|
// using Go's native iter.Seq and iter.Seq2 types. It follows functional programming
|
||||||
|
// principles and provides monadic operations, transformations, and reductions.
|
||||||
|
//
|
||||||
|
// The package supports:
|
||||||
|
// - Functor operations (Map, MapWithIndex, MapWithKey)
|
||||||
|
// - Monad operations (Chain, Flatten, Ap)
|
||||||
|
// - Filtering (Filter, FilterMap, FilterWithIndex, FilterWithKey)
|
||||||
|
// - Folding and reduction (Reduce, Fold, FoldMap)
|
||||||
|
// - Sequence construction (Of, From, MakeBy, Replicate)
|
||||||
|
// - Sequence combination (Zip, Prepend, Append)
|
||||||
|
//
|
||||||
|
// All operations are lazy and only execute when the sequence is consumed via iteration.
|
||||||
|
//
|
||||||
|
// Example usage:
|
||||||
|
//
|
||||||
|
// // Create a sequence and transform it
|
||||||
|
// seq := From(1, 2, 3, 4, 5)
|
||||||
|
// doubled := Map(func(x int) int { return x * 2 })(seq)
|
||||||
|
//
|
||||||
|
// // Filter and reduce
|
||||||
|
// evens := Filter(func(x int) bool { return x%2 == 0 })(doubled)
|
||||||
|
// sum := MonadReduce(evens, func(acc, x int) int { return acc + x }, 0)
|
||||||
|
// // sum = 20 (2+4+6+8+10 from doubled evens)
|
||||||
|
package iter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
I "iter"
|
||||||
|
|
||||||
|
F "github.com/IBM/fp-go/v2/function"
|
||||||
|
"github.com/IBM/fp-go/v2/internal/functor"
|
||||||
|
M "github.com/IBM/fp-go/v2/monoid"
|
||||||
|
"github.com/IBM/fp-go/v2/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Of creates a sequence containing a single element.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := Of(42)
|
||||||
|
// // yields: 42
|
||||||
|
func Of[A any](a A) Seq[A] {
|
||||||
|
return func(yield Predicate[A]) {
|
||||||
|
yield(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Of2 creates a key-value sequence containing a single key-value pair.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := Of2("key", 100)
|
||||||
|
// // yields: ("key", 100)
|
||||||
|
func Of2[K, A any](k K, a A) Seq2[K, A] {
|
||||||
|
return func(yield func(K, A) bool) {
|
||||||
|
yield(k, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadMap transforms each element in a sequence using the provided function.
|
||||||
|
// This is the monadic version that takes the sequence as the first parameter.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := From(1, 2, 3)
|
||||||
|
// result := MonadMap(seq, func(x int) int { return x * 2 })
|
||||||
|
// // yields: 2, 4, 6
|
||||||
|
func MonadMap[A, B any](as Seq[A], f func(A) B) Seq[B] {
|
||||||
|
return func(yield Predicate[B]) {
|
||||||
|
for a := range as {
|
||||||
|
if !yield(f(a)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map returns a function that transforms each element in a sequence.
|
||||||
|
// This is the curried version of MonadMap.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// double := Map(func(x int) int { return x * 2 })
|
||||||
|
// seq := From(1, 2, 3)
|
||||||
|
// result := double(seq)
|
||||||
|
// // yields: 2, 4, 6
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func Map[A, B any](f func(A) B) Operator[A, B] {
|
||||||
|
return F.Bind2nd(MonadMap[A, B], f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadMapWithIndex transforms each element in a sequence using a function that also receives the element's index.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := From("a", "b", "c")
|
||||||
|
// result := MonadMapWithIndex(seq, func(i int, s string) string {
|
||||||
|
// return fmt.Sprintf("%d:%s", i, s)
|
||||||
|
// })
|
||||||
|
// // yields: "0:a", "1:b", "2:c"
|
||||||
|
func MonadMapWithIndex[A, B any](as Seq[A], f func(int, A) B) Seq[B] {
|
||||||
|
return func(yield Predicate[B]) {
|
||||||
|
var i int
|
||||||
|
for a := range as {
|
||||||
|
if !yield(f(i, a)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapWithIndex returns a function that transforms elements with their indices.
|
||||||
|
// This is the curried version of MonadMapWithIndex.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// addIndex := MapWithIndex(func(i int, s string) string {
|
||||||
|
// return fmt.Sprintf("%d:%s", i, s)
|
||||||
|
// })
|
||||||
|
// seq := From("a", "b", "c")
|
||||||
|
// result := addIndex(seq)
|
||||||
|
// // yields: "0:a", "1:b", "2:c"
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func MapWithIndex[A, B any](f func(int, A) B) Operator[A, B] {
|
||||||
|
return F.Bind2nd(MonadMapWithIndex[A, B], f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadMapWithKey transforms values in a key-value sequence using a function that receives both key and value.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := Of2("x", 10)
|
||||||
|
// result := MonadMapWithKey(seq, func(k string, v int) int { return v * 2 })
|
||||||
|
// // yields: ("x", 20)
|
||||||
|
func MonadMapWithKey[K, A, B any](as Seq2[K, A], f func(K, A) B) Seq2[K, B] {
|
||||||
|
return func(yield func(K, B) bool) {
|
||||||
|
for k, a := range as {
|
||||||
|
if !yield(k, f(k, a)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapWithKey returns a function that transforms values using their keys.
|
||||||
|
// This is the curried version of MonadMapWithKey.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// doubleValue := MapWithKey(func(k string, v int) int { return v * 2 })
|
||||||
|
// seq := Of2("x", 10)
|
||||||
|
// result := doubleValue(seq)
|
||||||
|
// // yields: ("x", 20)
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func MapWithKey[K, A, B any](f func(K, A) B) Operator2[K, A, B] {
|
||||||
|
return F.Bind2nd(MonadMapWithKey[K, A, B], f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadFilter returns a sequence containing only elements that satisfy the predicate.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := From(1, 2, 3, 4, 5)
|
||||||
|
// result := MonadFilter(seq, func(x int) bool { return x%2 == 0 })
|
||||||
|
// // yields: 2, 4
|
||||||
|
func MonadFilter[A any](as Seq[A], pred func(A) bool) Seq[A] {
|
||||||
|
return func(yield Predicate[A]) {
|
||||||
|
for a := range as {
|
||||||
|
if pred(a) {
|
||||||
|
if !yield(a) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter returns a function that filters elements based on a predicate.
|
||||||
|
// This is the curried version of MonadFilter.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// evens := Filter(func(x int) bool { return x%2 == 0 })
|
||||||
|
// seq := From(1, 2, 3, 4, 5)
|
||||||
|
// result := evens(seq)
|
||||||
|
// // yields: 2, 4
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func Filter[A any](pred func(A) bool) Operator[A, A] {
|
||||||
|
return F.Bind2nd(MonadFilter[A], pred)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadFilterWithIndex filters elements using a predicate that also receives the element's index.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := From("a", "b", "c", "d")
|
||||||
|
// result := MonadFilterWithIndex(seq, func(i int, s string) bool { return i%2 == 0 })
|
||||||
|
// // yields: "a", "c" (elements at even indices)
|
||||||
|
func MonadFilterWithIndex[A any](as Seq[A], pred func(int, A) bool) Seq[A] {
|
||||||
|
return func(yield Predicate[A]) {
|
||||||
|
var i int
|
||||||
|
for a := range as {
|
||||||
|
if pred(i, a) {
|
||||||
|
if !yield(a) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterWithIndex returns a function that filters elements based on their index and value.
|
||||||
|
// This is the curried version of MonadFilterWithIndex.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// evenIndices := FilterWithIndex(func(i int, s string) bool { return i%2 == 0 })
|
||||||
|
// seq := From("a", "b", "c", "d")
|
||||||
|
// result := evenIndices(seq)
|
||||||
|
// // yields: "a", "c"
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func FilterWithIndex[A any](pred func(int, A) bool) Operator[A, A] {
|
||||||
|
return F.Bind2nd(MonadFilterWithIndex[A], pred)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadFilterWithKey filters key-value pairs using a predicate that receives both key and value.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := Of2("x", 10)
|
||||||
|
// result := MonadFilterWithKey(seq, func(k string, v int) bool { return v > 5 })
|
||||||
|
// // yields: ("x", 10)
|
||||||
|
func MonadFilterWithKey[K, A any](as Seq2[K, A], pred func(K, A) bool) Seq2[K, A] {
|
||||||
|
return func(yield func(K, A) bool) {
|
||||||
|
for k, a := range as {
|
||||||
|
if pred(k, a) {
|
||||||
|
if !yield(k, a) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterWithKey returns a function that filters key-value pairs based on a predicate.
|
||||||
|
// This is the curried version of MonadFilterWithKey.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// largeValues := FilterWithKey(func(k string, v int) bool { return v > 5 })
|
||||||
|
// seq := Of2("x", 10)
|
||||||
|
// result := largeValues(seq)
|
||||||
|
// // yields: ("x", 10)
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func FilterWithKey[K, A any](pred func(K, A) bool) Operator2[K, A, A] {
|
||||||
|
return F.Bind2nd(MonadFilterWithKey[K, A], pred)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadFilterMap applies a function that returns an Option to each element,
|
||||||
|
// keeping only the Some values and unwrapping them.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := From(1, 2, 3, 4, 5)
|
||||||
|
// result := MonadFilterMap(seq, func(x int) Option[int] {
|
||||||
|
// if x%2 == 0 {
|
||||||
|
// return option.Some(x * 10)
|
||||||
|
// }
|
||||||
|
// return option.None[int]()
|
||||||
|
// })
|
||||||
|
// // yields: 20, 40
|
||||||
|
func MonadFilterMap[A, B any](as Seq[A], f option.Kleisli[A, B]) Seq[B] {
|
||||||
|
return func(yield Predicate[B]) {
|
||||||
|
for a := range as {
|
||||||
|
if b, ok := option.Unwrap(f(a)); ok {
|
||||||
|
if !yield(b) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterMap returns a function that filters and maps in one operation.
|
||||||
|
// This is the curried version of MonadFilterMap.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// evenDoubled := FilterMap(func(x int) Option[int] {
|
||||||
|
// if x%2 == 0 {
|
||||||
|
// return option.Some(x * 2)
|
||||||
|
// }
|
||||||
|
// return option.None[int]()
|
||||||
|
// })
|
||||||
|
// seq := From(1, 2, 3, 4)
|
||||||
|
// result := evenDoubled(seq)
|
||||||
|
// // yields: 4, 8
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func FilterMap[A, B any](f option.Kleisli[A, B]) Operator[A, B] {
|
||||||
|
return F.Bind2nd(MonadFilterMap[A, B], f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadFilterMapWithIndex applies a function with index that returns an Option,
|
||||||
|
// keeping only the Some values.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := From("a", "b", "c")
|
||||||
|
// result := MonadFilterMapWithIndex(seq, func(i int, s string) Option[string] {
|
||||||
|
// if i%2 == 0 {
|
||||||
|
// return option.Some(fmt.Sprintf("%d:%s", i, s))
|
||||||
|
// }
|
||||||
|
// return option.None[string]()
|
||||||
|
// })
|
||||||
|
// // yields: "0:a", "2:c"
|
||||||
|
func MonadFilterMapWithIndex[A, B any](as Seq[A], f func(int, A) Option[B]) Seq[B] {
|
||||||
|
return func(yield Predicate[B]) {
|
||||||
|
var i int
|
||||||
|
for a := range as {
|
||||||
|
if b, ok := option.Unwrap(f(i, a)); ok {
|
||||||
|
if !yield(b) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterMapWithIndex returns a function that filters and maps with index.
|
||||||
|
// This is the curried version of MonadFilterMapWithIndex.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// evenIndexed := FilterMapWithIndex(func(i int, s string) Option[string] {
|
||||||
|
// if i%2 == 0 {
|
||||||
|
// return option.Some(s)
|
||||||
|
// }
|
||||||
|
// return option.None[string]()
|
||||||
|
// })
|
||||||
|
// seq := From("a", "b", "c", "d")
|
||||||
|
// result := evenIndexed(seq)
|
||||||
|
// // yields: "a", "c"
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func FilterMapWithIndex[A, B any](f func(int, A) Option[B]) Operator[A, B] {
|
||||||
|
return F.Bind2nd(MonadFilterMapWithIndex[A, B], f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadFilterMapWithKey applies a function with key that returns an Option to key-value pairs,
|
||||||
|
// keeping only the Some values.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := Of2("x", 10)
|
||||||
|
// result := MonadFilterMapWithKey(seq, func(k string, v int) Option[int] {
|
||||||
|
// if v > 5 {
|
||||||
|
// return option.Some(v * 2)
|
||||||
|
// }
|
||||||
|
// return option.None[int]()
|
||||||
|
// })
|
||||||
|
// // yields: ("x", 20)
|
||||||
|
func MonadFilterMapWithKey[K, A, B any](as Seq2[K, A], f func(K, A) Option[B]) Seq2[K, B] {
|
||||||
|
return func(yield func(K, B) bool) {
|
||||||
|
for k, a := range as {
|
||||||
|
if b, ok := option.Unwrap(f(k, a)); ok {
|
||||||
|
if !yield(k, b) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterMapWithKey returns a function that filters and maps key-value pairs.
|
||||||
|
// This is the curried version of MonadFilterMapWithKey.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// largeDoubled := FilterMapWithKey(func(k string, v int) Option[int] {
|
||||||
|
// if v > 5 {
|
||||||
|
// return option.Some(v * 2)
|
||||||
|
// }
|
||||||
|
// return option.None[int]()
|
||||||
|
// })
|
||||||
|
// seq := Of2("x", 10)
|
||||||
|
// result := largeDoubled(seq)
|
||||||
|
// // yields: ("x", 20)
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func FilterMapWithKey[K, A, B any](f func(K, A) Option[B]) Operator2[K, A, B] {
|
||||||
|
return F.Bind2nd(MonadFilterMapWithKey[K, A, B], f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadChain applies a function that returns a sequence to each element and flattens the results.
|
||||||
|
// This is the monadic bind operation (flatMap).
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := From(1, 2, 3)
|
||||||
|
// result := MonadChain(seq, func(x int) Seq[int] {
|
||||||
|
// return From(x, x*10)
|
||||||
|
// })
|
||||||
|
// // yields: 1, 10, 2, 20, 3, 30
|
||||||
|
func MonadChain[A, B any](as Seq[A], f Kleisli[A, B]) Seq[B] {
|
||||||
|
return func(yield Predicate[B]) {
|
||||||
|
for a := range as {
|
||||||
|
for b := range f(a) {
|
||||||
|
if !yield(b) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chain returns a function that chains (flatMaps) a sequence transformation.
|
||||||
|
// This is the curried version of MonadChain.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// duplicate := Chain(func(x int) Seq[int] { return From(x, x) })
|
||||||
|
// seq := From(1, 2, 3)
|
||||||
|
// result := duplicate(seq)
|
||||||
|
// // yields: 1, 1, 2, 2, 3, 3
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func Chain[A, B any](f func(A) Seq[B]) Operator[A, B] {
|
||||||
|
return F.Bind2nd(MonadChain[A, B], f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flatten flattens a sequence of sequences into a single sequence.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// nested := From(From(1, 2), From(3, 4), From(5))
|
||||||
|
// result := Flatten(nested)
|
||||||
|
// // yields: 1, 2, 3, 4, 5
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func Flatten[A any](mma Seq[Seq[A]]) Seq[A] {
|
||||||
|
return MonadChain(mma, F.Identity[Seq[A]])
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadAp applies a sequence of functions to a sequence of values.
|
||||||
|
// This is the applicative apply operation.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// fns := From(func(x int) int { return x * 2 }, func(x int) int { return x + 10 })
|
||||||
|
// vals := From(5, 3)
|
||||||
|
// result := MonadAp(fns, vals)
|
||||||
|
// // yields: 10, 6, 15, 13 (each function applied to each value)
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func MonadAp[B, A any](fab Seq[func(A) B], fa Seq[A]) Seq[B] {
|
||||||
|
return MonadChain(fab, F.Bind1st(MonadMap[A, B], fa))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ap returns a function that applies functions to values.
|
||||||
|
// This is the curried version of MonadAp.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// applyTo5 := Ap(From(5))
|
||||||
|
// fns := From(func(x int) int { return x * 2 }, func(x int) int { return x + 10 })
|
||||||
|
// result := applyTo5(fns)
|
||||||
|
// // yields: 10, 15
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func Ap[B, A any](fa Seq[A]) Operator[func(A) B, B] {
|
||||||
|
return F.Bind2nd(MonadAp[B, A], fa)
|
||||||
|
}
|
||||||
|
|
||||||
|
// From creates a sequence from a variadic list of elements.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := From(1, 2, 3, 4, 5)
|
||||||
|
// // yields: 1, 2, 3, 4, 5
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func From[A any](data ...A) Seq[A] {
|
||||||
|
return slices.Values(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty returns an empty sequence that yields no elements.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := Empty[int]()
|
||||||
|
// // yields nothing
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func Empty[A any]() Seq[A] {
|
||||||
|
return func(_ Predicate[A]) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeBy creates a sequence of n elements by applying a function to each index.
|
||||||
|
// Returns an empty sequence if n <= 0.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := MakeBy(5, func(i int) int { return i * i })
|
||||||
|
// // yields: 0, 1, 4, 9, 16
|
||||||
|
func MakeBy[A any](n int, f func(int) A) Seq[A] {
|
||||||
|
// sanity check
|
||||||
|
if n <= 0 {
|
||||||
|
return Empty[A]()
|
||||||
|
}
|
||||||
|
// run the generator function across the input
|
||||||
|
return func(yield Predicate[A]) {
|
||||||
|
for i := range n {
|
||||||
|
if !yield(f(i)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replicate creates a sequence containing n copies of the same element.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := Replicate(3, "hello")
|
||||||
|
// // yields: "hello", "hello", "hello"
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func Replicate[A any](n int, a A) Seq[A] {
|
||||||
|
return MakeBy(n, F.Constant1[int](a))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadReduce reduces a sequence to a single value by applying a function to each element
|
||||||
|
// and an accumulator, starting with an initial value.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := From(1, 2, 3, 4, 5)
|
||||||
|
// sum := MonadReduce(seq, func(acc, x int) int { return acc + x }, 0)
|
||||||
|
// // returns: 15
|
||||||
|
func MonadReduce[A, B any](fa Seq[A], f func(B, A) B, initial B) B {
|
||||||
|
current := initial
|
||||||
|
for a := range fa {
|
||||||
|
current = f(current, a)
|
||||||
|
}
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce returns a function that reduces a sequence to a single value.
|
||||||
|
// This is the curried version of MonadReduce.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// sum := Reduce(func(acc, x int) int { return acc + x }, 0)
|
||||||
|
// seq := From(1, 2, 3, 4, 5)
|
||||||
|
// result := sum(seq)
|
||||||
|
// // returns: 15
|
||||||
|
func Reduce[A, B any](f func(B, A) B, initial B) func(Seq[A]) B {
|
||||||
|
return func(fa Seq[A]) B {
|
||||||
|
return MonadReduce(fa, f, initial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadReduceWithIndex reduces a sequence using a function that also receives the element's index.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := From(10, 20, 30)
|
||||||
|
// result := MonadReduceWithIndex(seq, func(i, acc, x int) int {
|
||||||
|
// return acc + (i * x)
|
||||||
|
// }, 0)
|
||||||
|
// // returns: 0*10 + 1*20 + 2*30 = 80
|
||||||
|
func MonadReduceWithIndex[A, B any](fa Seq[A], f func(int, B, A) B, initial B) B {
|
||||||
|
current := initial
|
||||||
|
var i int
|
||||||
|
for a := range fa {
|
||||||
|
current = f(i, current, a)
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReduceWithIndex returns a function that reduces with index.
|
||||||
|
// This is the curried version of MonadReduceWithIndex.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// weightedSum := ReduceWithIndex(func(i, acc, x int) int {
|
||||||
|
// return acc + (i * x)
|
||||||
|
// }, 0)
|
||||||
|
// seq := From(10, 20, 30)
|
||||||
|
// result := weightedSum(seq)
|
||||||
|
// // returns: 80
|
||||||
|
func ReduceWithIndex[A, B any](f func(int, B, A) B, initial B) func(Seq[A]) B {
|
||||||
|
return func(fa Seq[A]) B {
|
||||||
|
return MonadReduceWithIndex(fa, f, initial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadReduceWithKey reduces a key-value sequence using a function that receives the key.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := Of2("x", 10)
|
||||||
|
// result := MonadReduceWithKey(seq, func(k string, acc int, v int) int {
|
||||||
|
// return acc + v
|
||||||
|
// }, 0)
|
||||||
|
// // returns: 10
|
||||||
|
func MonadReduceWithKey[K, A, B any](fa Seq2[K, A], f func(K, B, A) B, initial B) B {
|
||||||
|
current := initial
|
||||||
|
for k, a := range fa {
|
||||||
|
current = f(k, current, a)
|
||||||
|
}
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReduceWithKey returns a function that reduces key-value pairs.
|
||||||
|
// This is the curried version of MonadReduceWithKey.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// sumValues := ReduceWithKey(func(k string, acc int, v int) int {
|
||||||
|
// return acc + v
|
||||||
|
// }, 0)
|
||||||
|
// seq := Of2("x", 10)
|
||||||
|
// result := sumValues(seq)
|
||||||
|
// // returns: 10
|
||||||
|
func ReduceWithKey[K, A, B any](f func(K, B, A) B, initial B) func(Seq2[K, A]) B {
|
||||||
|
return func(fa Seq2[K, A]) B {
|
||||||
|
return MonadReduceWithKey(fa, f, initial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadFold folds a sequence using a monoid's concat operation and empty value.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// import "github.com/IBM/fp-go/v2/number"
|
||||||
|
// seq := From(1, 2, 3, 4, 5)
|
||||||
|
// sum := MonadFold(seq, number.MonoidSum[int]())
|
||||||
|
// // returns: 15
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func MonadFold[A any](fa Seq[A], m M.Monoid[A]) A {
|
||||||
|
return MonadReduce(fa, m.Concat, m.Empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fold returns a function that folds a sequence using a monoid.
|
||||||
|
// This is the curried version of MonadFold.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// import "github.com/IBM/fp-go/v2/number"
|
||||||
|
// sumAll := Fold(number.MonoidSum[int]())
|
||||||
|
// seq := From(1, 2, 3, 4, 5)
|
||||||
|
// result := sumAll(seq)
|
||||||
|
// // returns: 15
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func Fold[A any](m M.Monoid[A]) func(Seq[A]) A {
|
||||||
|
return Reduce(m.Concat, m.Empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadFoldMap maps each element to a monoid value and combines them using the monoid.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// import "github.com/IBM/fp-go/v2/string"
|
||||||
|
// seq := From(1, 2, 3)
|
||||||
|
// result := MonadFoldMap(seq, func(x int) string {
|
||||||
|
// return fmt.Sprintf("%d ", x)
|
||||||
|
// }, string.Monoid)
|
||||||
|
// // returns: "1 2 3 "
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func MonadFoldMap[A, B any](fa Seq[A], f func(A) B, m M.Monoid[B]) B {
|
||||||
|
return MonadReduce(fa, func(b B, a A) B {
|
||||||
|
return m.Concat(b, f(a))
|
||||||
|
}, m.Empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
// FoldMap returns a function that maps and folds using a monoid.
|
||||||
|
// This is the curried version of MonadFoldMap.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// import "github.com/IBM/fp-go/v2/string"
|
||||||
|
// stringify := FoldMap(string.Monoid)(func(x int) string {
|
||||||
|
// return fmt.Sprintf("%d ", x)
|
||||||
|
// })
|
||||||
|
// seq := From(1, 2, 3)
|
||||||
|
// result := stringify(seq)
|
||||||
|
// // returns: "1 2 3 "
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func FoldMap[A, B any](m M.Monoid[B]) func(func(A) B) func(Seq[A]) B {
|
||||||
|
return func(f func(A) B) func(Seq[A]) B {
|
||||||
|
return func(as Seq[A]) B {
|
||||||
|
return MonadFoldMap(as, f, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadFoldMapWithIndex maps each element with its index to a monoid value and combines them.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// import "github.com/IBM/fp-go/v2/string"
|
||||||
|
// seq := From("a", "b", "c")
|
||||||
|
// result := MonadFoldMapWithIndex(seq, func(i int, s string) string {
|
||||||
|
// return fmt.Sprintf("%d:%s ", i, s)
|
||||||
|
// }, string.Monoid)
|
||||||
|
// // returns: "0:a 1:b 2:c "
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func MonadFoldMapWithIndex[A, B any](fa Seq[A], f func(int, A) B, m M.Monoid[B]) B {
|
||||||
|
return MonadReduceWithIndex(fa, func(i int, b B, a A) B {
|
||||||
|
return m.Concat(b, f(i, a))
|
||||||
|
}, m.Empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
// FoldMapWithIndex returns a function that maps with index and folds.
|
||||||
|
// This is the curried version of MonadFoldMapWithIndex.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// import "github.com/IBM/fp-go/v2/string"
|
||||||
|
// indexedStringify := FoldMapWithIndex(string.Monoid)(func(i int, s string) string {
|
||||||
|
// return fmt.Sprintf("%d:%s ", i, s)
|
||||||
|
// })
|
||||||
|
// seq := From("a", "b", "c")
|
||||||
|
// result := indexedStringify(seq)
|
||||||
|
// // returns: "0:a 1:b 2:c "
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func FoldMapWithIndex[A, B any](m M.Monoid[B]) func(func(int, A) B) func(Seq[A]) B {
|
||||||
|
return func(f func(int, A) B) func(Seq[A]) B {
|
||||||
|
return func(as Seq[A]) B {
|
||||||
|
return MonadFoldMapWithIndex(as, f, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadFoldMapWithKey maps each key-value pair to a monoid value and combines them.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// import "github.com/IBM/fp-go/v2/string"
|
||||||
|
// seq := Of2("x", 10)
|
||||||
|
// result := MonadFoldMapWithKey(seq, func(k string, v int) string {
|
||||||
|
// return fmt.Sprintf("%s:%d ", k, v)
|
||||||
|
// }, string.Monoid)
|
||||||
|
// // returns: "x:10 "
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func MonadFoldMapWithKey[K, A, B any](fa Seq2[K, A], f func(K, A) B, m M.Monoid[B]) B {
|
||||||
|
return MonadReduceWithKey(fa, func(k K, b B, a A) B {
|
||||||
|
return m.Concat(b, f(k, a))
|
||||||
|
}, m.Empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
// FoldMapWithKey returns a function that maps with key and folds.
|
||||||
|
// This is the curried version of MonadFoldMapWithKey.
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func FoldMapWithKey[K, A, B any](m M.Monoid[B]) func(func(K, A) B) func(Seq2[K, A]) B {
|
||||||
|
return func(f func(K, A) B) func(Seq2[K, A]) B {
|
||||||
|
return func(as Seq2[K, A]) B {
|
||||||
|
return MonadFoldMapWithKey(as, f, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadFlap applies a fixed value to a sequence of functions.
|
||||||
|
// This is the dual of MonadAp.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// fns := From(func(x int) int { return x * 2 }, func(x int) int { return x + 10 })
|
||||||
|
// result := MonadFlap(fns, 5)
|
||||||
|
// // yields: 10, 15
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func MonadFlap[B, A any](fab Seq[func(A) B], a A) Seq[B] {
|
||||||
|
return functor.MonadFlap(MonadMap[func(A) B, B], fab, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flap returns a function that applies a fixed value to functions.
|
||||||
|
// This is the curried version of MonadFlap.
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func Flap[B, A any](a A) Operator[func(A) B, B] {
|
||||||
|
return functor.Flap(Map[func(A) B, B], a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepend returns a function that adds an element to the beginning of a sequence.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := From(2, 3, 4)
|
||||||
|
// result := Prepend(1)(seq)
|
||||||
|
// // yields: 1, 2, 3, 4
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func Prepend[A any](head A) Operator[A, A] {
|
||||||
|
return F.Bind1st(concat[A], Of(head))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append returns a function that adds an element to the end of a sequence.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seq := From(1, 2, 3)
|
||||||
|
// result := Append(4)(seq)
|
||||||
|
// // yields: 1, 2, 3, 4
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func Append[A any](tail A) Operator[A, A] {
|
||||||
|
return F.Bind2nd(concat[A], Of(tail))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonadZip combines two sequences into a sequence of pairs.
|
||||||
|
// The resulting sequence stops when either input sequence is exhausted.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seqA := From(1, 2, 3)
|
||||||
|
// seqB := From("a", "b")
|
||||||
|
// result := MonadZip(seqB, seqA)
|
||||||
|
// // yields: (1, "a"), (2, "b")
|
||||||
|
func MonadZip[A, B any](fb Seq[B], fa Seq[A]) Seq2[A, B] {
|
||||||
|
|
||||||
|
return func(yield func(A, B) bool) {
|
||||||
|
na, sa := I.Pull(fa)
|
||||||
|
defer sa()
|
||||||
|
|
||||||
|
for b := range fb {
|
||||||
|
a, ok := na()
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !yield(a, b) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zip returns a function that zips a sequence with another sequence.
|
||||||
|
// This is the curried version of MonadZip.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// seqA := From(1, 2, 3)
|
||||||
|
// zipWithA := Zip(seqA)
|
||||||
|
// seqB := From("a", "b", "c")
|
||||||
|
// result := zipWithA(seqB)
|
||||||
|
// // yields: (1, "a"), (2, "b"), (3, "c")
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func Zip[A, B any](fa Seq[A]) func(Seq[B]) Seq2[A, B] {
|
||||||
|
return F.Bind2nd(MonadZip[A, B], fa)
|
||||||
|
}
|
||||||
588
v2/iterator/iter/iter_test.go
Normal file
588
v2/iterator/iter/iter_test.go
Normal file
@@ -0,0 +1,588 @@
|
|||||||
|
// Copyright (c) 2023 - 2025 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package iter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"maps"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
F "github.com/IBM/fp-go/v2/function"
|
||||||
|
O "github.com/IBM/fp-go/v2/option"
|
||||||
|
S "github.com/IBM/fp-go/v2/string"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Helper function to collect sequence into a slice
|
||||||
|
func toSlice[T any](seq Seq[T]) []T {
|
||||||
|
return slices.Collect(seq)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to collect Seq2 into a map
|
||||||
|
func toMap[K comparable, V any](seq Seq2[K, V]) map[K]V {
|
||||||
|
return maps.Collect(seq)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOf(t *testing.T) {
|
||||||
|
seq := Of(42)
|
||||||
|
result := toSlice(seq)
|
||||||
|
assert.Equal(t, []int{42}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOf2(t *testing.T) {
|
||||||
|
seq := Of2("key", 100)
|
||||||
|
result := toMap(seq)
|
||||||
|
assert.Equal(t, map[string]int{"key": 100}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFrom(t *testing.T) {
|
||||||
|
seq := From(1, 2, 3, 4, 5)
|
||||||
|
result := toSlice(seq)
|
||||||
|
assert.Equal(t, []int{1, 2, 3, 4, 5}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmpty(t *testing.T) {
|
||||||
|
seq := Empty[int]()
|
||||||
|
result := toSlice(seq)
|
||||||
|
assert.Empty(t, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadMap(t *testing.T) {
|
||||||
|
seq := From(1, 2, 3)
|
||||||
|
doubled := MonadMap(seq, func(x int) int { return x * 2 })
|
||||||
|
result := toSlice(doubled)
|
||||||
|
assert.Equal(t, []int{2, 4, 6}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMap(t *testing.T) {
|
||||||
|
seq := From(1, 2, 3)
|
||||||
|
double := Map(func(x int) int { return x * 2 })
|
||||||
|
result := toSlice(double(seq))
|
||||||
|
assert.Equal(t, []int{2, 4, 6}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadMapWithIndex(t *testing.T) {
|
||||||
|
seq := From("a", "b", "c")
|
||||||
|
indexed := MonadMapWithIndex(seq, func(i int, s string) string {
|
||||||
|
return fmt.Sprintf("%d:%s", i, s)
|
||||||
|
})
|
||||||
|
result := toSlice(indexed)
|
||||||
|
assert.Equal(t, []string{"0:a", "1:b", "2:c"}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMapWithIndex(t *testing.T) {
|
||||||
|
seq := From("a", "b", "c")
|
||||||
|
indexer := MapWithIndex(func(i int, s string) string {
|
||||||
|
return fmt.Sprintf("%d:%s", i, s)
|
||||||
|
})
|
||||||
|
result := toSlice(indexer(seq))
|
||||||
|
assert.Equal(t, []string{"0:a", "1:b", "2:c"}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadMapWithKey(t *testing.T) {
|
||||||
|
seq := Of2("x", 10)
|
||||||
|
doubled := MonadMapWithKey(seq, func(k string, v int) int { return v * 2 })
|
||||||
|
result := toMap(doubled)
|
||||||
|
assert.Equal(t, map[string]int{"x": 20}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMapWithKey(t *testing.T) {
|
||||||
|
seq := Of2("x", 10)
|
||||||
|
doubler := MapWithKey(func(k string, v int) int { return v * 2 })
|
||||||
|
result := toMap(doubler(seq))
|
||||||
|
assert.Equal(t, map[string]int{"x": 20}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadFilter(t *testing.T) {
|
||||||
|
seq := From(1, 2, 3, 4, 5)
|
||||||
|
evens := MonadFilter(seq, func(x int) bool { return x%2 == 0 })
|
||||||
|
result := toSlice(evens)
|
||||||
|
assert.Equal(t, []int{2, 4}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilter(t *testing.T) {
|
||||||
|
seq := From(1, 2, 3, 4, 5)
|
||||||
|
isEven := Filter(func(x int) bool { return x%2 == 0 })
|
||||||
|
result := toSlice(isEven(seq))
|
||||||
|
assert.Equal(t, []int{2, 4}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadFilterWithIndex(t *testing.T) {
|
||||||
|
seq := From("a", "b", "c", "d")
|
||||||
|
oddIndices := MonadFilterWithIndex(seq, func(i int, _ string) bool { return i%2 == 1 })
|
||||||
|
result := toSlice(oddIndices)
|
||||||
|
assert.Equal(t, []string{"b", "d"}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterWithIndex(t *testing.T) {
|
||||||
|
seq := From("a", "b", "c", "d")
|
||||||
|
oddIndexFilter := FilterWithIndex(func(i int, _ string) bool { return i%2 == 1 })
|
||||||
|
result := toSlice(oddIndexFilter(seq))
|
||||||
|
assert.Equal(t, []string{"b", "d"}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadFilterWithKey(t *testing.T) {
|
||||||
|
seq := Of2("x", 10)
|
||||||
|
filtered := MonadFilterWithKey(seq, func(k string, v int) bool { return v > 5 })
|
||||||
|
result := toMap(filtered)
|
||||||
|
assert.Equal(t, map[string]int{"x": 10}, result)
|
||||||
|
|
||||||
|
seq2 := Of2("y", 3)
|
||||||
|
filtered2 := MonadFilterWithKey(seq2, func(k string, v int) bool { return v > 5 })
|
||||||
|
result2 := toMap(filtered2)
|
||||||
|
assert.Equal(t, map[string]int{}, result2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterWithKey(t *testing.T) {
|
||||||
|
seq := Of2("x", 10)
|
||||||
|
filter := FilterWithKey(func(k string, v int) bool { return v > 5 })
|
||||||
|
result := toMap(filter(seq))
|
||||||
|
assert.Equal(t, map[string]int{"x": 10}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadFilterMap(t *testing.T) {
|
||||||
|
seq := From(1, 2, 3, 4)
|
||||||
|
result := MonadFilterMap(seq, func(x int) Option[int] {
|
||||||
|
if x%2 == 0 {
|
||||||
|
return O.Some(x * 10)
|
||||||
|
}
|
||||||
|
return O.None[int]()
|
||||||
|
})
|
||||||
|
assert.Equal(t, []int{20, 40}, toSlice(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterMap(t *testing.T) {
|
||||||
|
seq := From(1, 2, 3, 4)
|
||||||
|
filterMapper := FilterMap(func(x int) Option[int] {
|
||||||
|
if x%2 == 0 {
|
||||||
|
return O.Some(x * 10)
|
||||||
|
}
|
||||||
|
return O.None[int]()
|
||||||
|
})
|
||||||
|
result := toSlice(filterMapper(seq))
|
||||||
|
assert.Equal(t, []int{20, 40}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadFilterMapWithIndex(t *testing.T) {
|
||||||
|
seq := From("a", "b", "c")
|
||||||
|
result := MonadFilterMapWithIndex(seq, func(i int, s string) Option[string] {
|
||||||
|
if i%2 == 0 {
|
||||||
|
return O.Some(strings.ToUpper(s))
|
||||||
|
}
|
||||||
|
return O.None[string]()
|
||||||
|
})
|
||||||
|
assert.Equal(t, []string{"A", "C"}, toSlice(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterMapWithIndex(t *testing.T) {
|
||||||
|
seq := From("a", "b", "c")
|
||||||
|
filterMapper := FilterMapWithIndex(func(i int, s string) Option[string] {
|
||||||
|
if i%2 == 0 {
|
||||||
|
return O.Some(strings.ToUpper(s))
|
||||||
|
}
|
||||||
|
return O.None[string]()
|
||||||
|
})
|
||||||
|
result := toSlice(filterMapper(seq))
|
||||||
|
assert.Equal(t, []string{"A", "C"}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadFilterMapWithKey(t *testing.T) {
|
||||||
|
seq := Of2("x", 10)
|
||||||
|
result := MonadFilterMapWithKey(seq, func(k string, v int) Option[int] {
|
||||||
|
if v > 5 {
|
||||||
|
return O.Some(v * 2)
|
||||||
|
}
|
||||||
|
return O.None[int]()
|
||||||
|
})
|
||||||
|
assert.Equal(t, map[string]int{"x": 20}, toMap(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterMapWithKey(t *testing.T) {
|
||||||
|
seq := Of2("x", 10)
|
||||||
|
filterMapper := FilterMapWithKey(func(k string, v int) Option[int] {
|
||||||
|
if v > 5 {
|
||||||
|
return O.Some(v * 2)
|
||||||
|
}
|
||||||
|
return O.None[int]()
|
||||||
|
})
|
||||||
|
result := toMap(filterMapper(seq))
|
||||||
|
assert.Equal(t, map[string]int{"x": 20}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadChain(t *testing.T) {
|
||||||
|
seq := From(1, 2)
|
||||||
|
result := MonadChain(seq, func(x int) Seq[int] {
|
||||||
|
return From(x, x*10)
|
||||||
|
})
|
||||||
|
assert.Equal(t, []int{1, 10, 2, 20}, toSlice(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChain(t *testing.T) {
|
||||||
|
seq := From(1, 2)
|
||||||
|
chainer := Chain(func(x int) Seq[int] {
|
||||||
|
return From(x, x*10)
|
||||||
|
})
|
||||||
|
result := toSlice(chainer(seq))
|
||||||
|
assert.Equal(t, []int{1, 10, 2, 20}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFlatten(t *testing.T) {
|
||||||
|
seq := From(From(1, 2), From(3, 4))
|
||||||
|
result := Flatten(seq)
|
||||||
|
assert.Equal(t, []int{1, 2, 3, 4}, toSlice(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadAp(t *testing.T) {
|
||||||
|
fns := From(
|
||||||
|
func(x int) int { return x * 2 },
|
||||||
|
func(x int) int { return x + 10 },
|
||||||
|
)
|
||||||
|
vals := From(1, 2)
|
||||||
|
result := MonadAp(fns, vals)
|
||||||
|
assert.Equal(t, []int{2, 4, 11, 12}, toSlice(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAp(t *testing.T) {
|
||||||
|
fns := From(
|
||||||
|
func(x int) int { return x * 2 },
|
||||||
|
func(x int) int { return x + 10 },
|
||||||
|
)
|
||||||
|
vals := From(1, 2)
|
||||||
|
applier := Ap[int](vals)
|
||||||
|
result := toSlice(applier(fns))
|
||||||
|
assert.Equal(t, []int{2, 4, 11, 12}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApCurried(t *testing.T) {
|
||||||
|
f := F.Curry3(func(s1 string, n int, s2 string) string {
|
||||||
|
return fmt.Sprintf("%s-%d-%s", s1, n, s2)
|
||||||
|
})
|
||||||
|
|
||||||
|
result := F.Pipe4(
|
||||||
|
Of(f),
|
||||||
|
Ap[func(int) func(string) string](From("a", "b")),
|
||||||
|
Ap[func(string) string](From(1, 2)),
|
||||||
|
Ap[string](From("c", "d")),
|
||||||
|
toSlice[string],
|
||||||
|
)
|
||||||
|
|
||||||
|
expected := []string{"a-1-c", "a-1-d", "a-2-c", "a-2-d", "b-1-c", "b-1-d", "b-2-c", "b-2-d"}
|
||||||
|
assert.Equal(t, expected, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMakeBy(t *testing.T) {
|
||||||
|
seq := MakeBy(5, func(i int) int { return i * i })
|
||||||
|
result := toSlice(seq)
|
||||||
|
assert.Equal(t, []int{0, 1, 4, 9, 16}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMakeByZero(t *testing.T) {
|
||||||
|
seq := MakeBy(0, func(i int) int { return i })
|
||||||
|
result := toSlice(seq)
|
||||||
|
assert.Empty(t, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMakeByNegative(t *testing.T) {
|
||||||
|
seq := MakeBy(-5, func(i int) int { return i })
|
||||||
|
result := toSlice(seq)
|
||||||
|
assert.Empty(t, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReplicate(t *testing.T) {
|
||||||
|
seq := Replicate(3, "hello")
|
||||||
|
result := toSlice(seq)
|
||||||
|
assert.Equal(t, []string{"hello", "hello", "hello"}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadReduce(t *testing.T) {
|
||||||
|
seq := From(1, 2, 3, 4)
|
||||||
|
sum := MonadReduce(seq, func(acc, x int) int { return acc + x }, 0)
|
||||||
|
assert.Equal(t, 10, sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReduce(t *testing.T) {
|
||||||
|
seq := From(1, 2, 3, 4)
|
||||||
|
sum := Reduce(func(acc, x int) int { return acc + x }, 0)
|
||||||
|
result := sum(seq)
|
||||||
|
assert.Equal(t, 10, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadReduceWithIndex(t *testing.T) {
|
||||||
|
seq := From(10, 20, 30)
|
||||||
|
result := MonadReduceWithIndex(seq, func(i, acc, x int) int {
|
||||||
|
return acc + (i * x)
|
||||||
|
}, 0)
|
||||||
|
// 0*10 + 1*20 + 2*30 = 0 + 20 + 60 = 80
|
||||||
|
assert.Equal(t, 80, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReduceWithIndex(t *testing.T) {
|
||||||
|
seq := From(10, 20, 30)
|
||||||
|
reducer := ReduceWithIndex(func(i, acc, x int) int {
|
||||||
|
return acc + (i * x)
|
||||||
|
}, 0)
|
||||||
|
result := reducer(seq)
|
||||||
|
assert.Equal(t, 80, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadReduceWithKey(t *testing.T) {
|
||||||
|
seq := Of2("x", 10)
|
||||||
|
result := MonadReduceWithKey(seq, func(k string, acc, v int) int {
|
||||||
|
return acc + v
|
||||||
|
}, 0)
|
||||||
|
assert.Equal(t, 10, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReduceWithKey(t *testing.T) {
|
||||||
|
seq := Of2("x", 10)
|
||||||
|
reducer := ReduceWithKey(func(k string, acc, v int) int {
|
||||||
|
return acc + v
|
||||||
|
}, 0)
|
||||||
|
result := reducer(seq)
|
||||||
|
assert.Equal(t, 10, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadFold(t *testing.T) {
|
||||||
|
seq := From("Hello", " ", "World")
|
||||||
|
result := MonadFold(seq, S.Monoid)
|
||||||
|
assert.Equal(t, "Hello World", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFold(t *testing.T) {
|
||||||
|
seq := From("Hello", " ", "World")
|
||||||
|
folder := Fold(S.Monoid)
|
||||||
|
result := folder(seq)
|
||||||
|
assert.Equal(t, "Hello World", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadFoldMap(t *testing.T) {
|
||||||
|
seq := From(1, 2, 3)
|
||||||
|
result := MonadFoldMap(seq, func(x int) string {
|
||||||
|
return fmt.Sprintf("%d", x)
|
||||||
|
}, S.Monoid)
|
||||||
|
assert.Equal(t, "123", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFoldMap(t *testing.T) {
|
||||||
|
seq := From(1, 2, 3)
|
||||||
|
folder := FoldMap[int](S.Monoid)(func(x int) string {
|
||||||
|
return fmt.Sprintf("%d", x)
|
||||||
|
})
|
||||||
|
result := folder(seq)
|
||||||
|
assert.Equal(t, "123", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadFoldMapWithIndex(t *testing.T) {
|
||||||
|
seq := From("a", "b", "c")
|
||||||
|
result := MonadFoldMapWithIndex(seq, func(i int, s string) string {
|
||||||
|
return fmt.Sprintf("%d:%s ", i, s)
|
||||||
|
}, S.Monoid)
|
||||||
|
assert.Equal(t, "0:a 1:b 2:c ", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFoldMapWithIndex(t *testing.T) {
|
||||||
|
seq := From("a", "b", "c")
|
||||||
|
folder := FoldMapWithIndex[string](S.Monoid)(func(i int, s string) string {
|
||||||
|
return fmt.Sprintf("%d:%s ", i, s)
|
||||||
|
})
|
||||||
|
result := folder(seq)
|
||||||
|
assert.Equal(t, "0:a 1:b 2:c ", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadFoldMapWithKey(t *testing.T) {
|
||||||
|
seq := Of2("x", 10)
|
||||||
|
result := MonadFoldMapWithKey(seq, func(k string, v int) string {
|
||||||
|
return fmt.Sprintf("%s:%d ", k, v)
|
||||||
|
}, S.Monoid)
|
||||||
|
assert.Equal(t, "x:10 ", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFoldMapWithKey(t *testing.T) {
|
||||||
|
seq := Of2("x", 10)
|
||||||
|
folder := FoldMapWithKey[string, int](S.Monoid)(func(k string, v int) string {
|
||||||
|
return fmt.Sprintf("%s:%d ", k, v)
|
||||||
|
})
|
||||||
|
result := folder(seq)
|
||||||
|
assert.Equal(t, "x:10 ", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadFlap(t *testing.T) {
|
||||||
|
fns := From(
|
||||||
|
func(x int) int { return x * 2 },
|
||||||
|
func(x int) int { return x + 10 },
|
||||||
|
)
|
||||||
|
result := MonadFlap(fns, 5)
|
||||||
|
assert.Equal(t, []int{10, 15}, toSlice(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFlap(t *testing.T) {
|
||||||
|
fns := From(
|
||||||
|
func(x int) int { return x * 2 },
|
||||||
|
func(x int) int { return x + 10 },
|
||||||
|
)
|
||||||
|
flapper := Flap[int](5)
|
||||||
|
result := toSlice(flapper(fns))
|
||||||
|
assert.Equal(t, []int{10, 15}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrepend(t *testing.T) {
|
||||||
|
seq := From(2, 3, 4)
|
||||||
|
result := Prepend(1)(seq)
|
||||||
|
assert.Equal(t, []int{1, 2, 3, 4}, toSlice(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppend(t *testing.T) {
|
||||||
|
seq := From(1, 2, 3)
|
||||||
|
result := Append(4)(seq)
|
||||||
|
assert.Equal(t, []int{1, 2, 3, 4}, toSlice(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonadZip(t *testing.T) {
|
||||||
|
seqA := From(1, 2, 3)
|
||||||
|
seqB := From("a", "b")
|
||||||
|
result := MonadZip(seqB, seqA)
|
||||||
|
|
||||||
|
var pairs []string
|
||||||
|
for a, b := range result {
|
||||||
|
pairs = append(pairs, fmt.Sprintf("%d:%s", a, b))
|
||||||
|
}
|
||||||
|
assert.Equal(t, []string{"1:a", "2:b"}, pairs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestZip(t *testing.T) {
|
||||||
|
seqA := From(1, 2, 3)
|
||||||
|
seqB := From("a", "b", "c")
|
||||||
|
zipWithA := Zip[int, string](seqA)
|
||||||
|
result := zipWithA(seqB)
|
||||||
|
|
||||||
|
var pairs []string
|
||||||
|
for a, b := range result {
|
||||||
|
pairs = append(pairs, fmt.Sprintf("%d:%s", a, b))
|
||||||
|
}
|
||||||
|
assert.Equal(t, []string{"1:a", "2:b", "3:c"}, pairs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonoid(t *testing.T) {
|
||||||
|
m := Monoid[int]()
|
||||||
|
seq1 := From(1, 2)
|
||||||
|
seq2 := From(3, 4)
|
||||||
|
result := m.Concat(seq1, seq2)
|
||||||
|
assert.Equal(t, []int{1, 2, 3, 4}, toSlice(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonoidEmpty(t *testing.T) {
|
||||||
|
m := Monoid[int]()
|
||||||
|
empty := m.Empty()
|
||||||
|
assert.Empty(t, toSlice(empty))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonoidAssociativity(t *testing.T) {
|
||||||
|
m := Monoid[int]()
|
||||||
|
seq1 := From(1, 2)
|
||||||
|
seq2 := From(3, 4)
|
||||||
|
seq3 := From(5, 6)
|
||||||
|
|
||||||
|
// (seq1 + seq2) + seq3
|
||||||
|
left := m.Concat(m.Concat(seq1, seq2), seq3)
|
||||||
|
// seq1 + (seq2 + seq3)
|
||||||
|
right := m.Concat(seq1, m.Concat(seq2, seq3))
|
||||||
|
|
||||||
|
assert.Equal(t, toSlice(left), toSlice(right))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonoidIdentity(t *testing.T) {
|
||||||
|
m := Monoid[int]()
|
||||||
|
seq := From(1, 2, 3)
|
||||||
|
empty := m.Empty()
|
||||||
|
|
||||||
|
// seq + empty = seq
|
||||||
|
leftIdentity := m.Concat(seq, empty)
|
||||||
|
assert.Equal(t, []int{1, 2, 3}, toSlice(leftIdentity))
|
||||||
|
|
||||||
|
// empty + seq = seq
|
||||||
|
rightIdentity := m.Concat(empty, seq)
|
||||||
|
assert.Equal(t, []int{1, 2, 3}, toSlice(rightIdentity))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPipelineComposition(t *testing.T) {
|
||||||
|
// Test a complex pipeline
|
||||||
|
result := F.Pipe4(
|
||||||
|
From(1, 2, 3, 4, 5, 6),
|
||||||
|
Filter(func(x int) bool { return x%2 == 0 }),
|
||||||
|
Map(func(x int) int { return x * 10 }),
|
||||||
|
Prepend(0),
|
||||||
|
toSlice[int],
|
||||||
|
)
|
||||||
|
assert.Equal(t, []int{0, 20, 40, 60}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLazyEvaluation(t *testing.T) {
|
||||||
|
// Test that operations are lazy
|
||||||
|
callCount := 0
|
||||||
|
seq := From(1, 2, 3, 4, 5)
|
||||||
|
mapped := MonadMap(seq, func(x int) int {
|
||||||
|
callCount++
|
||||||
|
return x * 2
|
||||||
|
})
|
||||||
|
|
||||||
|
// No calls yet since we haven't iterated
|
||||||
|
assert.Equal(t, 0, callCount)
|
||||||
|
|
||||||
|
// Iterate only first 2 elements
|
||||||
|
count := 0
|
||||||
|
for range mapped {
|
||||||
|
count++
|
||||||
|
if count == 2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should have called the function only twice
|
||||||
|
assert.Equal(t, 2, callCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleFoldMap() {
|
||||||
|
seq := From("a", "b", "c")
|
||||||
|
fold := FoldMap[string](S.Monoid)(strings.ToUpper)
|
||||||
|
result := fold(seq)
|
||||||
|
fmt.Println(result)
|
||||||
|
// Output: ABC
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleChain() {
|
||||||
|
seq := From(1, 2)
|
||||||
|
result := F.Pipe2(
|
||||||
|
seq,
|
||||||
|
Chain(func(x int) Seq[int] {
|
||||||
|
return From(x, x*10)
|
||||||
|
}),
|
||||||
|
toSlice[int],
|
||||||
|
)
|
||||||
|
fmt.Println(result)
|
||||||
|
// Output: [1 10 2 20]
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleMonoid() {
|
||||||
|
m := Monoid[int]()
|
||||||
|
seq1 := From(1, 2, 3)
|
||||||
|
seq2 := From(4, 5, 6)
|
||||||
|
combined := m.Concat(seq1, seq2)
|
||||||
|
result := toSlice(combined)
|
||||||
|
fmt.Println(result)
|
||||||
|
// Output: [1 2 3 4 5 6]
|
||||||
|
}
|
||||||
52
v2/iterator/iter/monid.go
Normal file
52
v2/iterator/iter/monid.go
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (c) 2023 - 2025 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package iter
|
||||||
|
|
||||||
|
import (
|
||||||
|
M "github.com/IBM/fp-go/v2/monoid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// concat concatenates two sequences, yielding all elements from left followed by all elements from right.
|
||||||
|
func concat[T any](left, right Seq[T]) Seq[T] {
|
||||||
|
return func(yield Predicate[T]) {
|
||||||
|
for t := range left {
|
||||||
|
if !yield(t) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for t := range right {
|
||||||
|
if !yield(t) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Monoid returns a Monoid instance for Seq[T].
|
||||||
|
// The monoid's concat operation concatenates sequences, and the empty value is an empty sequence.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// m := Monoid[int]()
|
||||||
|
// seq1 := From(1, 2)
|
||||||
|
// seq2 := From(3, 4)
|
||||||
|
// result := m.Concat(seq1, seq2)
|
||||||
|
// // yields: 1, 2, 3, 4
|
||||||
|
//
|
||||||
|
//go:inline
|
||||||
|
func Monoid[T any]() M.Monoid[Seq[T]] {
|
||||||
|
return M.MakeMonoid(concat[T], Empty[T]())
|
||||||
|
}
|
||||||
57
v2/iterator/iter/types.go
Normal file
57
v2/iterator/iter/types.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// Copyright (c) 2023 - 2025 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package iter
|
||||||
|
|
||||||
|
import (
|
||||||
|
I "iter"
|
||||||
|
|
||||||
|
"github.com/IBM/fp-go/v2/iterator/stateless"
|
||||||
|
"github.com/IBM/fp-go/v2/optics/lens/option"
|
||||||
|
"github.com/IBM/fp-go/v2/predicate"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Option represents an optional value, either Some(value) or None.
|
||||||
|
Option[A any] = option.Option[A]
|
||||||
|
|
||||||
|
// Seq is a single-value iterator sequence from Go 1.23+.
|
||||||
|
// It represents a lazy sequence of values that can be iterated using range.
|
||||||
|
Seq[T any] = I.Seq[T]
|
||||||
|
|
||||||
|
// Seq2 is a key-value iterator sequence from Go 1.23+.
|
||||||
|
// It represents a lazy sequence of key-value pairs that can be iterated using range.
|
||||||
|
Seq2[K, V any] = I.Seq2[K, V]
|
||||||
|
|
||||||
|
// Iterator is a stateless iterator type.
|
||||||
|
Iterator[T any] = stateless.Iterator[T]
|
||||||
|
|
||||||
|
// Predicate is a function that tests a value and returns a boolean.
|
||||||
|
Predicate[T any] = predicate.Predicate[T]
|
||||||
|
|
||||||
|
// Kleisli represents a function that takes a value and returns a sequence.
|
||||||
|
// This is the monadic bind operation for sequences.
|
||||||
|
Kleisli[A, B any] = func(A) Seq[B]
|
||||||
|
|
||||||
|
// Kleisli2 represents a function that takes a value and returns a key-value sequence.
|
||||||
|
Kleisli2[K, A, B any] = func(A) Seq2[K, B]
|
||||||
|
|
||||||
|
// Operator represents a transformation from one sequence to another.
|
||||||
|
// It's a function that takes a Seq[A] and returns a Seq[B].
|
||||||
|
Operator[A, B any] = Kleisli[Seq[A], B]
|
||||||
|
|
||||||
|
// Operator2 represents a transformation from one key-value sequence to another.
|
||||||
|
Operator2[K, A, B any] = Kleisli2[K, Seq2[K, A], B]
|
||||||
|
)
|
||||||
@@ -21,6 +21,6 @@ import (
|
|||||||
|
|
||||||
// Any returns `true` if any element of the iterable is `true`. If the iterable is empty, return `false`
|
// Any returns `true` if any element of the iterable is `true`. If the iterable is empty, return `false`
|
||||||
// Similar to the [https://docs.python.org/3/library/functions.html#any] function
|
// Similar to the [https://docs.python.org/3/library/functions.html#any] function
|
||||||
func Any[U any](pred func(U) bool) func(ma Iterator[U]) bool {
|
func Any[U any](pred Predicate[U]) Predicate[Iterator[U]] {
|
||||||
return G.Any[Iterator[U]](pred)
|
return G.Any[Iterator[U]](pred)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ func Do[S any](
|
|||||||
func Bind[S1, S2, T any](
|
func Bind[S1, S2, T any](
|
||||||
setter func(T) func(S1) S2,
|
setter func(T) func(S1) S2,
|
||||||
f Kleisli[S1, T],
|
f Kleisli[S1, T],
|
||||||
) Kleisli[Iterator[S1], S2] {
|
) Operator[S1, S2] {
|
||||||
return G.Bind[Iterator[S1], Iterator[S2]](setter, f)
|
return G.Bind[Iterator[S1], Iterator[S2]](setter, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ func Bind[S1, S2, T any](
|
|||||||
func Let[S1, S2, T any](
|
func Let[S1, S2, T any](
|
||||||
setter func(T) func(S1) S2,
|
setter func(T) func(S1) S2,
|
||||||
f func(S1) T,
|
f func(S1) T,
|
||||||
) Kleisli[Iterator[S1], S2] {
|
) Operator[S1, S2] {
|
||||||
return G.Let[Iterator[S1], Iterator[S2]](setter, f)
|
return G.Let[Iterator[S1], Iterator[S2]](setter, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,14 +88,14 @@ func Let[S1, S2, T any](
|
|||||||
func LetTo[S1, S2, T any](
|
func LetTo[S1, S2, T any](
|
||||||
setter func(T) func(S1) S2,
|
setter func(T) func(S1) S2,
|
||||||
b T,
|
b T,
|
||||||
) Kleisli[Iterator[S1], S2] {
|
) Operator[S1, S2] {
|
||||||
return G.LetTo[Iterator[S1], Iterator[S2]](setter, b)
|
return G.LetTo[Iterator[S1], Iterator[S2]](setter, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BindTo initializes a new state [S1] from a value [T]
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
func BindTo[S1, T any](
|
func BindTo[S1, T any](
|
||||||
setter func(T) S1,
|
setter func(T) S1,
|
||||||
) Kleisli[Iterator[T], S1] {
|
) Operator[T, S1] {
|
||||||
return G.BindTo[Iterator[S1], Iterator[T]](setter)
|
return G.BindTo[Iterator[S1], Iterator[T]](setter)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,6 +135,6 @@ func BindTo[S1, T any](
|
|||||||
func ApS[S1, S2, T any](
|
func ApS[S1, S2, T any](
|
||||||
setter func(T) func(S1) S2,
|
setter func(T) func(S1) S2,
|
||||||
fa Iterator[T],
|
fa Iterator[T],
|
||||||
) Kleisli[Iterator[S1], S2] {
|
) Operator[S1, S2] {
|
||||||
return G.ApS[Iterator[func(T) S2], Iterator[S1], Iterator[S2]](setter, fa)
|
return G.ApS[Iterator[func(T) S2], Iterator[S1], Iterator[S2]](setter, fa)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,10 @@ package stateless
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
G "github.com/IBM/fp-go/v2/iterator/stateless/generic"
|
G "github.com/IBM/fp-go/v2/iterator/stateless/generic"
|
||||||
P "github.com/IBM/fp-go/v2/pair"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Compress returns an [Iterator] that filters elements from a data [Iterator] returning only those that have a corresponding element in selector [Iterator] that evaluates to `true`.
|
// Compress returns an [Iterator] that filters elements from a data [Iterator] returning only those that have a corresponding element in selector [Iterator] that evaluates to `true`.
|
||||||
// Stops when either the data or selectors iterator has been exhausted.
|
// Stops when either the data or selectors iterator has been exhausted.
|
||||||
func Compress[U any](sel Iterator[bool]) Kleisli[Iterator[U], U] {
|
func Compress[U any](sel Iterator[bool]) Operator[U, U] {
|
||||||
return G.Compress[Iterator[U], Iterator[bool], Iterator[P.Pair[U, bool]]](sel)
|
return G.Compress[Iterator[U], Iterator[bool], Iterator[Pair[U, bool]]](sel)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,6 @@ import (
|
|||||||
|
|
||||||
// DropWhile creates an [Iterator] that drops elements from the [Iterator] as long as the predicate is true; afterwards, returns every element.
|
// DropWhile creates an [Iterator] that drops elements from the [Iterator] as long as the predicate is true; afterwards, returns every element.
|
||||||
// Note, the [Iterator] does not produce any output until the predicate first becomes false
|
// Note, the [Iterator] does not produce any output until the predicate first becomes false
|
||||||
func DropWhile[U any](pred func(U) bool) Kleisli[Iterator[U], U] {
|
func DropWhile[U any](pred Predicate[U]) Operator[U, U] {
|
||||||
return G.DropWhile[Iterator[U]](pred)
|
return G.DropWhile[Iterator[U]](pred)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,9 @@ package stateless
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
G "github.com/IBM/fp-go/v2/iterator/stateless/generic"
|
G "github.com/IBM/fp-go/v2/iterator/stateless/generic"
|
||||||
O "github.com/IBM/fp-go/v2/option"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// First returns the first item in an iterator if such an item exists
|
// First returns the first item in an iterator if such an item exists
|
||||||
func First[U any](mu Iterator[U]) O.Option[U] {
|
func First[U any](mu Iterator[U]) Option[U] {
|
||||||
return G.First(mu)
|
return G.First(mu)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,11 +18,10 @@ package generic
|
|||||||
import (
|
import (
|
||||||
F "github.com/IBM/fp-go/v2/function"
|
F "github.com/IBM/fp-go/v2/function"
|
||||||
O "github.com/IBM/fp-go/v2/option"
|
O "github.com/IBM/fp-go/v2/option"
|
||||||
P "github.com/IBM/fp-go/v2/pair"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Any returns `true` if any element of the iterable is `true`. If the iterable is empty, return `false`
|
// Any returns `true` if any element of the iterable is `true`. If the iterable is empty, return `false`
|
||||||
func Any[GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(U) bool, U any](pred FCT) func(ma GU) bool {
|
func Any[GU ~func() Option[Pair[GU, U]], FCT ~Predicate[U], U any](pred FCT) func(ma GU) bool {
|
||||||
return F.Flow3(
|
return F.Flow3(
|
||||||
Filter[GU](pred),
|
Filter[GU](pred),
|
||||||
First[GU],
|
First[GU],
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ import (
|
|||||||
"github.com/IBM/fp-go/v2/internal/apply"
|
"github.com/IBM/fp-go/v2/internal/apply"
|
||||||
C "github.com/IBM/fp-go/v2/internal/chain"
|
C "github.com/IBM/fp-go/v2/internal/chain"
|
||||||
F "github.com/IBM/fp-go/v2/internal/functor"
|
F "github.com/IBM/fp-go/v2/internal/functor"
|
||||||
O "github.com/IBM/fp-go/v2/option"
|
|
||||||
P "github.com/IBM/fp-go/v2/pair"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Do creates an empty context of type [S] to be used with the [Bind] operation.
|
// Do creates an empty context of type [S] to be used with the [Bind] operation.
|
||||||
@@ -33,7 +31,7 @@ import (
|
|||||||
// Y int
|
// Y int
|
||||||
// }
|
// }
|
||||||
// result := generic.Do[Iterator[State]](State{})
|
// result := generic.Do[Iterator[State]](State{})
|
||||||
func Do[GS ~func() O.Option[P.Pair[GS, S]], S any](
|
func Do[GS ~func() Option[Pair[GS, S]], S any](
|
||||||
empty S,
|
empty S,
|
||||||
) GS {
|
) GS {
|
||||||
return Of[GS](empty)
|
return Of[GS](empty)
|
||||||
@@ -73,7 +71,7 @@ func Do[GS ~func() O.Option[P.Pair[GS, S]], S any](
|
|||||||
// },
|
// },
|
||||||
// ),
|
// ),
|
||||||
// ) // Produces: {1,10}, {1,20}, {2,20}, {2,40}, {3,30}, {3,60}
|
// ) // Produces: {1,10}, {1,20}, {2,20}, {2,40}, {3,30}, {3,60}
|
||||||
func Bind[GS1 ~func() O.Option[P.Pair[GS1, S1]], GS2 ~func() O.Option[P.Pair[GS2, S2]], GA ~func() O.Option[P.Pair[GA, A]], S1, S2, A any](
|
func Bind[GS1 ~func() Option[Pair[GS1, S1]], GS2 ~func() Option[Pair[GS2, S2]], GA ~func() Option[Pair[GA, A]], S1, S2, A any](
|
||||||
setter func(A) func(S1) S2,
|
setter func(A) func(S1) S2,
|
||||||
f func(S1) GA,
|
f func(S1) GA,
|
||||||
) func(GS1) GS2 {
|
) func(GS1) GS2 {
|
||||||
@@ -87,7 +85,7 @@ func Bind[GS1 ~func() O.Option[P.Pair[GS1, S1]], GS2 ~func() O.Option[P.Pair[GS2
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
func Let[GS1 ~func() O.Option[P.Pair[GS1, S1]], GS2 ~func() O.Option[P.Pair[GS2, S2]], S1, S2, A any](
|
func Let[GS1 ~func() Option[Pair[GS1, S1]], GS2 ~func() Option[Pair[GS2, S2]], S1, S2, A any](
|
||||||
key func(A) func(S1) S2,
|
key func(A) func(S1) S2,
|
||||||
f func(S1) A,
|
f func(S1) A,
|
||||||
) func(GS1) GS2 {
|
) func(GS1) GS2 {
|
||||||
@@ -99,7 +97,7 @@ func Let[GS1 ~func() O.Option[P.Pair[GS1, S1]], GS2 ~func() O.Option[P.Pair[GS2,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
func LetTo[GS1 ~func() O.Option[P.Pair[GS1, S1]], GS2 ~func() O.Option[P.Pair[GS2, S2]], S1, S2, B any](
|
func LetTo[GS1 ~func() Option[Pair[GS1, S1]], GS2 ~func() Option[Pair[GS2, S2]], S1, S2, B any](
|
||||||
key func(B) func(S1) S2,
|
key func(B) func(S1) S2,
|
||||||
b B,
|
b B,
|
||||||
) func(GS1) GS2 {
|
) func(GS1) GS2 {
|
||||||
@@ -111,7 +109,7 @@ func LetTo[GS1 ~func() O.Option[P.Pair[GS1, S1]], GS2 ~func() O.Option[P.Pair[GS
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BindTo initializes a new state [S1] from a value [T]
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
func BindTo[GS1 ~func() O.Option[P.Pair[GS1, S1]], GA ~func() O.Option[P.Pair[GA, A]], S1, A any](
|
func BindTo[GS1 ~func() Option[Pair[GS1, S1]], GA ~func() Option[Pair[GA, A]], S1, A any](
|
||||||
setter func(A) S1,
|
setter func(A) S1,
|
||||||
) func(GA) GS1 {
|
) func(GA) GS1 {
|
||||||
return C.BindTo(
|
return C.BindTo(
|
||||||
@@ -153,7 +151,7 @@ func BindTo[GS1 ~func() O.Option[P.Pair[GS1, S1]], GA ~func() O.Option[P.Pair[GA
|
|||||||
// yIter,
|
// yIter,
|
||||||
// ),
|
// ),
|
||||||
// ) // Produces: {1,"a"}, {1,"b"}, {2,"a"}, {2,"b"}, {3,"a"}, {3,"b"}
|
// ) // Produces: {1,"a"}, {1,"b"}, {2,"a"}, {2,"b"}, {3,"a"}, {3,"b"}
|
||||||
func ApS[GAS2 ~func() O.Option[P.Pair[GAS2, func(A) S2]], GS1 ~func() O.Option[P.Pair[GS1, S1]], GS2 ~func() O.Option[P.Pair[GS2, S2]], GA ~func() O.Option[P.Pair[GA, A]], S1, S2, A any](
|
func ApS[GAS2 ~func() Option[Pair[GAS2, func(A) S2]], GS1 ~func() Option[Pair[GS1, S1]], GS2 ~func() Option[Pair[GS2, S2]], GA ~func() Option[Pair[GA, A]], S1, S2, A any](
|
||||||
setter func(A) func(S1) S2,
|
setter func(A) func(S1) S2,
|
||||||
fa GA,
|
fa GA,
|
||||||
) func(GS1) GS2 {
|
) func(GS1) GS2 {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import (
|
|||||||
|
|
||||||
// Compress returns an [Iterator] that filters elements from a data [Iterator] returning only those that have a corresponding element in selector [Iterator] that evaluates to `true`.
|
// Compress returns an [Iterator] that filters elements from a data [Iterator] returning only those that have a corresponding element in selector [Iterator] that evaluates to `true`.
|
||||||
// Stops when either the data or selectors iterator has been exhausted.
|
// Stops when either the data or selectors iterator has been exhausted.
|
||||||
func Compress[GU ~func() O.Option[P.Pair[GU, U]], GB ~func() O.Option[P.Pair[GB, bool]], CS ~func() O.Option[P.Pair[CS, P.Pair[U, bool]]], U any](sel GB) func(GU) GU {
|
func Compress[GU ~func() Option[Pair[GU, U]], GB ~func() Option[Pair[GB, bool]], CS ~func() Option[Pair[CS, Pair[U, bool]]], U any](sel GB) func(GU) GU {
|
||||||
return F.Flow2(
|
return F.Flow2(
|
||||||
Zip[GU, GB, CS](sel),
|
Zip[GU, GB, CS](sel),
|
||||||
FilterMap[GU, CS](F.Flow2(
|
FilterMap[GU, CS](F.Flow2(
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ import (
|
|||||||
P "github.com/IBM/fp-go/v2/pair"
|
P "github.com/IBM/fp-go/v2/pair"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Cycle[GU ~func() O.Option[P.Pair[GU, U]], U any](ma GU) GU {
|
func Cycle[GU ~func() Option[Pair[GU, U]], U any](ma GU) GU {
|
||||||
// avoid cyclic references
|
// avoid cyclic references
|
||||||
var m func(O.Option[P.Pair[GU, U]]) O.Option[P.Pair[GU, U]]
|
var m func(Option[Pair[GU, U]]) Option[Pair[GU, U]]
|
||||||
|
|
||||||
recurse := func(mu GU) GU {
|
recurse := func(mu GU) GU {
|
||||||
return F.Nullary2(
|
return F.Nullary2(
|
||||||
@@ -32,11 +32,11 @@ func Cycle[GU ~func() O.Option[P.Pair[GU, U]], U any](ma GU) GU {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
m = O.Fold(func() O.Option[P.Pair[GU, U]] {
|
m = O.Fold(func() Option[Pair[GU, U]] {
|
||||||
return recurse(ma)()
|
return recurse(ma)()
|
||||||
}, F.Flow2(
|
}, F.Flow2(
|
||||||
P.BiMap(recurse, F.Identity[U]),
|
P.BiMap(recurse, F.Identity[U]),
|
||||||
O.Of[P.Pair[GU, U]],
|
O.Of[Pair[GU, U]],
|
||||||
))
|
))
|
||||||
|
|
||||||
return recurse(ma)
|
return recurse(ma)
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ import (
|
|||||||
|
|
||||||
// DropWhile creates an [Iterator] that drops elements from the [Iterator] as long as the predicate is true; afterwards, returns every element.
|
// DropWhile creates an [Iterator] that drops elements from the [Iterator] as long as the predicate is true; afterwards, returns every element.
|
||||||
// Note, the [Iterator] does not produce any output until the predicate first becomes false
|
// Note, the [Iterator] does not produce any output until the predicate first becomes false
|
||||||
func DropWhile[GU ~func() O.Option[P.Pair[GU, U]], U any](pred func(U) bool) func(GU) GU {
|
func DropWhile[GU ~func() Option[Pair[GU, U]], U any](pred Predicate[U]) func(GU) GU {
|
||||||
// avoid cyclic references
|
// avoid cyclic references
|
||||||
var m func(O.Option[P.Pair[GU, U]]) O.Option[P.Pair[GU, U]]
|
var m func(Option[Pair[GU, U]]) Option[Pair[GU, U]]
|
||||||
|
|
||||||
fromPred := O.FromPredicate(PR.Not(PR.ContraMap(P.Tail[GU, U])(pred)))
|
fromPred := O.FromPredicate(PR.Not(PR.ContraMap(P.Tail[GU, U])(pred)))
|
||||||
|
|
||||||
@@ -37,11 +37,11 @@ func DropWhile[GU ~func() O.Option[P.Pair[GU, U]], U any](pred func(U) bool) fun
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
m = O.Chain(func(t P.Pair[GU, U]) O.Option[P.Pair[GU, U]] {
|
m = O.Chain(func(t Pair[GU, U]) Option[Pair[GU, U]] {
|
||||||
return F.Pipe2(
|
return F.Pipe2(
|
||||||
t,
|
t,
|
||||||
fromPred,
|
fromPred,
|
||||||
O.Fold(recurse(Next(t)), O.Of[P.Pair[GU, U]]),
|
O.Fold(recurse(Next(t)), O.Of[Pair[GU, U]]),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// First returns the first item in an iterator if such an item exists
|
// First returns the first item in an iterator if such an item exists
|
||||||
func First[GU ~func() O.Option[P.Pair[GU, U]], U any](mu GU) O.Option[U] {
|
func First[GU ~func() Option[Pair[GU, U]], U any](mu GU) Option[U] {
|
||||||
return F.Pipe1(
|
return F.Pipe1(
|
||||||
mu(),
|
mu(),
|
||||||
O.Map(P.Tail[GU, U]),
|
O.Map(P.Tail[GU, U]),
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// FromLazy returns an iterator on top of a lazy function
|
// FromLazy returns an iterator on top of a lazy function
|
||||||
func FromLazy[GU ~func() O.Option[P.Pair[GU, U]], LZ ~func() U, U any](l LZ) GU {
|
func FromLazy[GU ~func() Option[Pair[GU, U]], LZ ~func() U, U any](l LZ) GU {
|
||||||
return F.Pipe1(
|
return F.Pipe1(
|
||||||
l,
|
l,
|
||||||
L.Map[LZ, GU](F.Flow2(
|
L.Map[LZ, GU](F.Flow2(
|
||||||
F.Bind1st(P.MakePair[GU, U], Empty[GU]()),
|
F.Bind1st(P.MakePair[GU, U], Empty[GU]()),
|
||||||
O.Of[P.Pair[GU, U]],
|
O.Of[Pair[GU, U]],
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,42 +27,42 @@ import (
|
|||||||
P "github.com/IBM/fp-go/v2/pair"
|
P "github.com/IBM/fp-go/v2/pair"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Next returns the iterator for the next element in an iterator `P.Pair`
|
// Next returns the iterator for the next element in an iterator `Pair`
|
||||||
func Next[GU ~func() O.Option[P.Pair[GU, U]], U any](m P.Pair[GU, U]) GU {
|
func Next[GU ~func() Option[Pair[GU, U]], U any](m Pair[GU, U]) GU {
|
||||||
return P.Head(m)
|
return P.Head(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current returns the current element in an iterator `P.Pair`
|
// Current returns the current element in an iterator `Pair`
|
||||||
func Current[GU ~func() O.Option[P.Pair[GU, U]], U any](m P.Pair[GU, U]) U {
|
func Current[GU ~func() Option[Pair[GU, U]], U any](m Pair[GU, U]) U {
|
||||||
return P.Tail(m)
|
return P.Tail(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// From constructs an array from a set of variadic arguments
|
// From constructs an array from a set of variadic arguments
|
||||||
func From[GU ~func() O.Option[P.Pair[GU, U]], U any](data ...U) GU {
|
func From[GU ~func() Option[Pair[GU, U]], U any](data ...U) GU {
|
||||||
return FromArray[GU](data)
|
return FromArray[GU](data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty returns the empty iterator
|
// Empty returns the empty iterator
|
||||||
func Empty[GU ~func() O.Option[P.Pair[GU, U]], U any]() GU {
|
func Empty[GU ~func() Option[Pair[GU, U]], U any]() GU {
|
||||||
return IO.None[GU]()
|
return IO.None[GU]()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Of returns an iterator with one single element
|
// Of returns an iterator with one single element
|
||||||
func Of[GU ~func() O.Option[P.Pair[GU, U]], U any](a U) GU {
|
func Of[GU ~func() Option[Pair[GU, U]], U any](a U) GU {
|
||||||
return IO.Of[GU](P.MakePair(Empty[GU](), a))
|
return IO.Of[GU](P.MakePair(Empty[GU](), a))
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromArray returns an iterator from multiple elements
|
// FromArray returns an iterator from multiple elements
|
||||||
func FromArray[GU ~func() O.Option[P.Pair[GU, U]], US ~[]U, U any](as US) GU {
|
func FromArray[GU ~func() Option[Pair[GU, U]], US ~[]U, U any](as US) GU {
|
||||||
return A.MatchLeft(Empty[GU], func(head U, tail US) GU {
|
return A.MatchLeft(Empty[GU], func(head U, tail US) GU {
|
||||||
return func() O.Option[P.Pair[GU, U]] {
|
return func() Option[Pair[GU, U]] {
|
||||||
return O.Of(P.MakePair(FromArray[GU](tail), head))
|
return O.Of(P.MakePair(FromArray[GU](tail), head))
|
||||||
}
|
}
|
||||||
})(as)
|
})(as)
|
||||||
}
|
}
|
||||||
|
|
||||||
// reduce applies a function for each value of the iterator with a floating result
|
// reduce applies a function for each value of the iterator with a floating result
|
||||||
func reduce[GU ~func() O.Option[P.Pair[GU, U]], U, V any](as GU, f func(V, U) V, initial V) V {
|
func reduce[GU ~func() Option[Pair[GU, U]], U, V any](as GU, f func(V, U) V, initial V) V {
|
||||||
next, ok := O.Unwrap(as())
|
next, ok := O.Unwrap(as())
|
||||||
current := initial
|
current := initial
|
||||||
for ok {
|
for ok {
|
||||||
@@ -74,18 +74,18 @@ func reduce[GU ~func() O.Option[P.Pair[GU, U]], U, V any](as GU, f func(V, U) V,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reduce applies a function for each value of the iterator with a floating result
|
// Reduce applies a function for each value of the iterator with a floating result
|
||||||
func Reduce[GU ~func() O.Option[P.Pair[GU, U]], U, V any](f func(V, U) V, initial V) func(GU) V {
|
func Reduce[GU ~func() Option[Pair[GU, U]], U, V any](f func(V, U) V, initial V) func(GU) V {
|
||||||
return F.Bind23of3(reduce[GU, U, V])(f, initial)
|
return F.Bind23of3(reduce[GU, U, V])(f, initial)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToArray converts the iterator to an array
|
// ToArray converts the iterator to an array
|
||||||
func ToArray[GU ~func() O.Option[P.Pair[GU, U]], US ~[]U, U any](u GU) US {
|
func ToArray[GU ~func() Option[Pair[GU, U]], US ~[]U, U any](u GU) US {
|
||||||
return Reduce[GU](A.Append[US], A.Empty[US]())(u)
|
return Reduce[GU](A.Append[US], A.Empty[US]())(u)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Map[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(U) V, U, V any](f FCT) func(ma GU) GV {
|
func Map[GV ~func() Option[Pair[GV, V]], GU ~func() Option[Pair[GU, U]], FCT ~func(U) V, U, V any](f FCT) func(ma GU) GV {
|
||||||
// pre-declare to avoid cyclic reference
|
// pre-declare to avoid cyclic reference
|
||||||
var m func(O.Option[P.Pair[GU, U]]) O.Option[P.Pair[GV, V]]
|
var m func(Option[Pair[GU, U]]) Option[Pair[GV, V]]
|
||||||
|
|
||||||
recurse := func(ma GU) GV {
|
recurse := func(ma GU) GV {
|
||||||
return F.Nullary2(
|
return F.Nullary2(
|
||||||
@@ -99,12 +99,12 @@ func Map[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]],
|
|||||||
return recurse
|
return recurse
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadMap[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], U, V any](ma GU, f func(U) V) GV {
|
func MonadMap[GV ~func() Option[Pair[GV, V]], GU ~func() Option[Pair[GU, U]], U, V any](ma GU, f func(U) V) GV {
|
||||||
return Map[GV, GU](f)(ma)
|
return Map[GV, GU](f)(ma)
|
||||||
}
|
}
|
||||||
|
|
||||||
func concat[GU ~func() O.Option[P.Pair[GU, U]], U any](right, left GU) GU {
|
func concat[GU ~func() Option[Pair[GU, U]], U any](right, left GU) GU {
|
||||||
var m func(ma O.Option[P.Pair[GU, U]]) O.Option[P.Pair[GU, U]]
|
var m func(ma Option[Pair[GU, U]]) Option[Pair[GU, U]]
|
||||||
|
|
||||||
recurse := func(left GU) GU {
|
recurse := func(left GU) GU {
|
||||||
return F.Nullary2(left, m)
|
return F.Nullary2(left, m)
|
||||||
@@ -114,15 +114,15 @@ func concat[GU ~func() O.Option[P.Pair[GU, U]], U any](right, left GU) GU {
|
|||||||
right,
|
right,
|
||||||
F.Flow2(
|
F.Flow2(
|
||||||
P.BiMap(recurse, F.Identity[U]),
|
P.BiMap(recurse, F.Identity[U]),
|
||||||
O.Some[P.Pair[GU, U]],
|
O.Some[Pair[GU, U]],
|
||||||
))
|
))
|
||||||
|
|
||||||
return recurse(left)
|
return recurse(left)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Chain[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], U, V any](f func(U) GV) func(GU) GV {
|
func Chain[GV ~func() Option[Pair[GV, V]], GU ~func() Option[Pair[GU, U]], U, V any](f func(U) GV) func(GU) GV {
|
||||||
// pre-declare to avoid cyclic reference
|
// pre-declare to avoid cyclic reference
|
||||||
var m func(O.Option[P.Pair[GU, U]]) O.Option[P.Pair[GV, V]]
|
var m func(Option[Pair[GU, U]]) Option[Pair[GV, V]]
|
||||||
|
|
||||||
recurse := func(ma GU) GV {
|
recurse := func(ma GU) GV {
|
||||||
return F.Nullary2(
|
return F.Nullary2(
|
||||||
@@ -134,7 +134,7 @@ func Chain[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]
|
|||||||
F.Flow3(
|
F.Flow3(
|
||||||
P.BiMap(recurse, f),
|
P.BiMap(recurse, f),
|
||||||
P.Paired(concat[GV]),
|
P.Paired(concat[GV]),
|
||||||
func(v GV) O.Option[P.Pair[GV, V]] {
|
func(v GV) Option[Pair[GV, V]] {
|
||||||
return v()
|
return v()
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -143,11 +143,11 @@ func Chain[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]
|
|||||||
return recurse
|
return recurse
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadChain[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], U, V any](ma GU, f func(U) GV) GV {
|
func MonadChain[GV ~func() Option[Pair[GV, V]], GU ~func() Option[Pair[GU, U]], U, V any](ma GU, f func(U) GV) GV {
|
||||||
return Chain[GV, GU](f)(ma)
|
return Chain[GV, GU](f)(ma)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadChainFirst[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], U, V any](ma GU, f func(U) GV) GU {
|
func MonadChainFirst[GV ~func() Option[Pair[GV, V]], GU ~func() Option[Pair[GU, U]], U, V any](ma GU, f func(U) GV) GU {
|
||||||
return C.MonadChainFirst(
|
return C.MonadChainFirst(
|
||||||
MonadChain[GU, GU, U, U],
|
MonadChain[GU, GU, U, U],
|
||||||
MonadMap[GU, GV, V, U],
|
MonadMap[GU, GV, V, U],
|
||||||
@@ -156,7 +156,7 @@ func MonadChainFirst[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.P
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChainFirst[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], U, V any](f func(U) GV) func(GU) GU {
|
func ChainFirst[GV ~func() Option[Pair[GV, V]], GU ~func() Option[Pair[GU, U]], U, V any](f func(U) GV) func(GU) GU {
|
||||||
return C.ChainFirst(
|
return C.ChainFirst(
|
||||||
Chain[GU, GU, U, U],
|
Chain[GU, GU, U, U],
|
||||||
Map[GU, GV, func(V) U, V, U],
|
Map[GU, GV, func(V) U, V, U],
|
||||||
@@ -164,14 +164,14 @@ func ChainFirst[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[G
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Flatten[GV ~func() O.Option[P.Pair[GV, GU]], GU ~func() O.Option[P.Pair[GU, U]], U any](ma GV) GU {
|
func Flatten[GV ~func() Option[Pair[GV, GU]], GU ~func() Option[Pair[GU, U]], U any](ma GV) GU {
|
||||||
return MonadChain(ma, F.Identity[GU])
|
return MonadChain(ma, F.Identity[GU])
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeBy returns an [Iterator] with an infinite number of elements initialized with `f(i)`
|
// MakeBy returns an [Iterator] with an infinite number of elements initialized with `f(i)`
|
||||||
func MakeBy[GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(int) U, U any](f FCT) GU {
|
func MakeBy[GU ~func() Option[Pair[GU, U]], FCT ~func(int) U, U any](f FCT) GU {
|
||||||
|
|
||||||
var m func(int) O.Option[P.Pair[GU, U]]
|
var m func(int) Option[Pair[GU, U]]
|
||||||
|
|
||||||
recurse := func(i int) GU {
|
recurse := func(i int) GU {
|
||||||
return F.Nullary2(
|
return F.Nullary2(
|
||||||
@@ -186,7 +186,7 @@ func MakeBy[GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(int) U, U any](f FCT)
|
|||||||
utils.Inc,
|
utils.Inc,
|
||||||
recurse),
|
recurse),
|
||||||
f),
|
f),
|
||||||
O.Of[P.Pair[GU, U]],
|
O.Of[Pair[GU, U]],
|
||||||
)
|
)
|
||||||
|
|
||||||
// bootstrap
|
// bootstrap
|
||||||
@@ -194,13 +194,13 @@ func MakeBy[GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(int) U, U any](f FCT)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Replicate creates an infinite [Iterator] containing a value.
|
// Replicate creates an infinite [Iterator] containing a value.
|
||||||
func Replicate[GU ~func() O.Option[P.Pair[GU, U]], U any](a U) GU {
|
func Replicate[GU ~func() Option[Pair[GU, U]], U any](a U) GU {
|
||||||
return MakeBy[GU](F.Constant1[int](a))
|
return MakeBy[GU](F.Constant1[int](a))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repeat creates an [Iterator] containing a value repeated the specified number of times.
|
// Repeat creates an [Iterator] containing a value repeated the specified number of times.
|
||||||
// Alias of [Replicate] combined with [Take]
|
// Alias of [Replicate] combined with [Take]
|
||||||
func Repeat[GU ~func() O.Option[P.Pair[GU, U]], U any](n int, a U) GU {
|
func Repeat[GU ~func() Option[Pair[GU, U]], U any](n int, a U) GU {
|
||||||
return F.Pipe2(
|
return F.Pipe2(
|
||||||
a,
|
a,
|
||||||
Replicate[GU],
|
Replicate[GU],
|
||||||
@@ -209,13 +209,13 @@ func Repeat[GU ~func() O.Option[P.Pair[GU, U]], U any](n int, a U) GU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Count creates an [Iterator] containing a consecutive sequence of integers starting with the provided start value
|
// Count creates an [Iterator] containing a consecutive sequence of integers starting with the provided start value
|
||||||
func Count[GU ~func() O.Option[P.Pair[GU, int]]](start int) GU {
|
func Count[GU ~func() Option[Pair[GU, int]]](start int) GU {
|
||||||
return MakeBy[GU](N.Add(start))
|
return MakeBy[GU](N.Add(start))
|
||||||
}
|
}
|
||||||
|
|
||||||
func FilterMap[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(U) O.Option[V], U, V any](f FCT) func(ma GU) GV {
|
func FilterMap[GV ~func() Option[Pair[GV, V]], GU ~func() Option[Pair[GU, U]], FCT ~func(U) Option[V], U, V any](f FCT) func(ma GU) GV {
|
||||||
// pre-declare to avoid cyclic reference
|
// pre-declare to avoid cyclic reference
|
||||||
var m func(O.Option[P.Pair[GU, U]]) O.Option[P.Pair[GV, V]]
|
var m func(Option[Pair[GU, U]]) Option[Pair[GV, V]]
|
||||||
|
|
||||||
recurse := func(ma GU) GV {
|
recurse := func(ma GU) GV {
|
||||||
return F.Nullary2(
|
return F.Nullary2(
|
||||||
@@ -226,11 +226,11 @@ func FilterMap[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU
|
|||||||
|
|
||||||
m = O.Fold(
|
m = O.Fold(
|
||||||
Empty[GV](),
|
Empty[GV](),
|
||||||
func(t P.Pair[GU, U]) O.Option[P.Pair[GV, V]] {
|
func(t Pair[GU, U]) Option[Pair[GV, V]] {
|
||||||
r := recurse(Next(t))
|
r := recurse(Next(t))
|
||||||
return O.MonadFold(f(Current(t)), r, F.Flow2(
|
return O.MonadFold(f(Current(t)), r, F.Flow2(
|
||||||
F.Bind1st(P.MakePair[GV, V], r),
|
F.Bind1st(P.MakePair[GV, V], r),
|
||||||
O.Some[P.Pair[GV, V]],
|
O.Some[Pair[GV, V]],
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -238,26 +238,26 @@ func FilterMap[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU
|
|||||||
return recurse
|
return recurse
|
||||||
}
|
}
|
||||||
|
|
||||||
func Filter[GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(U) bool, U any](f FCT) func(ma GU) GU {
|
func Filter[GU ~func() Option[Pair[GU, U]], FCT ~Predicate[U], U any](f FCT) func(ma GU) GU {
|
||||||
return FilterMap[GU, GU](O.FromPredicate(f))
|
return FilterMap[GU, GU](O.FromPredicate(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
func Ap[GUV ~func() O.Option[P.Pair[GUV, func(U) V]], GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], U, V any](ma GU) func(fab GUV) GV {
|
func Ap[GUV ~func() Option[Pair[GUV, func(U) V]], GV ~func() Option[Pair[GV, V]], GU ~func() Option[Pair[GU, U]], U, V any](ma GU) func(fab GUV) GV {
|
||||||
return Chain[GV, GUV](F.Bind1st(MonadMap[GV, GU], ma))
|
return Chain[GV, GUV](F.Bind1st(MonadMap[GV, GU], ma))
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadAp[GUV ~func() O.Option[P.Pair[GUV, func(U) V]], GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], U, V any](fab GUV, ma GU) GV {
|
func MonadAp[GUV ~func() Option[Pair[GUV, func(U) V]], GV ~func() Option[Pair[GV, V]], GU ~func() Option[Pair[GU, U]], U, V any](fab GUV, ma GU) GV {
|
||||||
return Ap[GUV, GV](ma)(fab)
|
return Ap[GUV, GV](ma)(fab)
|
||||||
}
|
}
|
||||||
|
|
||||||
func FilterChain[GVV ~func() O.Option[P.Pair[GVV, GV]], GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(U) O.Option[GV], U, V any](f FCT) func(ma GU) GV {
|
func FilterChain[GVV ~func() Option[Pair[GVV, GV]], GV ~func() Option[Pair[GV, V]], GU ~func() Option[Pair[GU, U]], FCT ~func(U) Option[GV], U, V any](f FCT) func(ma GU) GV {
|
||||||
return F.Flow2(
|
return F.Flow2(
|
||||||
FilterMap[GVV, GU](f),
|
FilterMap[GVV, GU](f),
|
||||||
Flatten[GVV],
|
Flatten[GVV],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func FoldMap[GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(U) V, U, V any](m M.Monoid[V]) func(FCT) func(ma GU) V {
|
func FoldMap[GU ~func() Option[Pair[GU, U]], FCT ~func(U) V, U, V any](m M.Monoid[V]) func(FCT) func(ma GU) V {
|
||||||
return func(f FCT) func(ma GU) V {
|
return func(f FCT) func(ma GU) V {
|
||||||
return Reduce[GU](func(cur V, a U) V {
|
return Reduce[GU](func(cur V, a U) V {
|
||||||
return m.Concat(cur, f(a))
|
return m.Concat(cur, f(a))
|
||||||
@@ -265,6 +265,6 @@ func FoldMap[GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(U) V, U, V any](m M.M
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Fold[GU ~func() O.Option[P.Pair[GU, U]], U any](m M.Monoid[U]) func(ma GU) U {
|
func Fold[GU ~func() Option[Pair[GU, U]], U any](m M.Monoid[U]) func(ma GU) U {
|
||||||
return Reduce[GU](m.Concat, m.Empty())
|
return Reduce[GU](m.Concat, m.Empty())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,10 +18,9 @@ package generic
|
|||||||
import (
|
import (
|
||||||
F "github.com/IBM/fp-go/v2/function"
|
F "github.com/IBM/fp-go/v2/function"
|
||||||
O "github.com/IBM/fp-go/v2/option"
|
O "github.com/IBM/fp-go/v2/option"
|
||||||
P "github.com/IBM/fp-go/v2/pair"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Last returns the last item in an iterator if such an item exists
|
// Last returns the last item in an iterator if such an item exists
|
||||||
func Last[GU ~func() O.Option[P.Pair[GU, U]], U any](mu GU) O.Option[U] {
|
func Last[GU ~func() Option[Pair[GU, U]], U any](mu GU) Option[U] {
|
||||||
return reduce(mu, F.Ignore1of2[O.Option[U]](O.Of[U]), O.None[U]())
|
return reduce(mu, F.Ignore1of2[Option[U]](O.Of[U]), O.None[U]())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,9 @@ package generic
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/IBM/fp-go/v2/internal/monad"
|
"github.com/IBM/fp-go/v2/internal/monad"
|
||||||
O "github.com/IBM/fp-go/v2/option"
|
|
||||||
P "github.com/IBM/fp-go/v2/pair"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type iteratorMonad[A, B any, GA ~func() O.Option[P.Pair[GA, A]], GB ~func() O.Option[P.Pair[GB, B]], GAB ~func() O.Option[P.Pair[GAB, func(A) B]]] struct{}
|
type iteratorMonad[A, B any, GA ~func() Option[Pair[GA, A]], GB ~func() Option[Pair[GB, B]], GAB ~func() Option[Pair[GAB, func(A) B]]] struct{}
|
||||||
|
|
||||||
func (o *iteratorMonad[A, B, GA, GB, GAB]) Of(a A) GA {
|
func (o *iteratorMonad[A, B, GA, GB, GAB]) Of(a A) GA {
|
||||||
return Of[GA](a)
|
return Of[GA](a)
|
||||||
@@ -40,6 +38,6 @@ func (o *iteratorMonad[A, B, GA, GB, GAB]) Ap(fa GA) func(GAB) GB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Monad implements the monadic operations for iterators
|
// Monad implements the monadic operations for iterators
|
||||||
func Monad[A, B any, GA ~func() O.Option[P.Pair[GA, A]], GB ~func() O.Option[P.Pair[GB, B]], GAB ~func() O.Option[P.Pair[GAB, func(A) B]]]() monad.Monad[A, B, GA, GB, GAB] {
|
func Monad[A, B any, GA ~func() Option[Pair[GA, A]], GB ~func() Option[Pair[GB, B]], GAB ~func() Option[Pair[GAB, func(A) B]]]() monad.Monad[A, B, GA, GB, GAB] {
|
||||||
return &iteratorMonad[A, B, GA, GB, GAB]{}
|
return &iteratorMonad[A, B, GA, GB, GAB]{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,11 +18,9 @@ package generic
|
|||||||
import (
|
import (
|
||||||
F "github.com/IBM/fp-go/v2/function"
|
F "github.com/IBM/fp-go/v2/function"
|
||||||
M "github.com/IBM/fp-go/v2/monoid"
|
M "github.com/IBM/fp-go/v2/monoid"
|
||||||
O "github.com/IBM/fp-go/v2/option"
|
|
||||||
P "github.com/IBM/fp-go/v2/pair"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Monoid[GU ~func() O.Option[P.Pair[GU, U]], U any]() M.Monoid[GU] {
|
func Monoid[GU ~func() Option[Pair[GU, U]], U any]() M.Monoid[GU] {
|
||||||
return M.MakeMonoid(
|
return M.MakeMonoid(
|
||||||
F.Swap(concat[GU]),
|
F.Swap(concat[GU]),
|
||||||
Empty[GU](),
|
Empty[GU](),
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import (
|
|||||||
P "github.com/IBM/fp-go/v2/pair"
|
P "github.com/IBM/fp-go/v2/pair"
|
||||||
)
|
)
|
||||||
|
|
||||||
func FromReflect[GR ~func() O.Option[P.Pair[GR, R.Value]]](val R.Value) GR {
|
func FromReflect[GR ~func() Option[Pair[GR, R.Value]]](val R.Value) GR {
|
||||||
// recursive callback
|
// recursive callback
|
||||||
var recurse func(idx int) GR
|
var recurse func(idx int) GR
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ func FromReflect[GR ~func() O.Option[P.Pair[GR, R.Value]]](val R.Value) GR {
|
|||||||
idx,
|
idx,
|
||||||
L.Of[int],
|
L.Of[int],
|
||||||
L.Map(fromPred),
|
L.Map(fromPred),
|
||||||
LG.Map[L.Lazy[O.Option[int]], GR](O.Map(
|
LG.Map[Lazy[Option[int]], GR](O.Map(
|
||||||
F.Flow2(
|
F.Flow2(
|
||||||
P.Of[int],
|
P.Of[int],
|
||||||
P.BiMap(F.Flow2(N.Add(1), recurse), val.Index),
|
P.BiMap(F.Flow2(N.Add(1), recurse), val.Index),
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ import (
|
|||||||
P "github.com/IBM/fp-go/v2/pair"
|
P "github.com/IBM/fp-go/v2/pair"
|
||||||
)
|
)
|
||||||
|
|
||||||
func apTuple[A, B any](t P.Pair[func(A) B, A]) P.Pair[B, A] {
|
func apTuple[A, B any](t Pair[func(A) B, A]) Pair[B, A] {
|
||||||
return P.MakePair(P.Head(t)(P.Tail(t)), P.Tail(t))
|
return P.MakePair(P.Head(t)(P.Tail(t)), P.Tail(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
func Scan[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(V, U) V, U, V any](f FCT, initial V) func(ma GU) GV {
|
func Scan[GV ~func() Option[Pair[GV, V]], GU ~func() Option[Pair[GU, U]], FCT ~func(V, U) V, U, V any](f FCT, initial V) func(ma GU) GV {
|
||||||
// pre-declare to avoid cyclic reference
|
// pre-declare to avoid cyclic reference
|
||||||
var m func(GU) func(V) GV
|
var m func(GU) func(V) GV
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import (
|
|||||||
P "github.com/IBM/fp-go/v2/pair"
|
P "github.com/IBM/fp-go/v2/pair"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Take[GU ~func() O.Option[P.Pair[GU, U]], U any](n int) func(ma GU) GU {
|
func Take[GU ~func() Option[Pair[GU, U]], U any](n int) func(ma GU) GU {
|
||||||
// pre-declare to avoid cyclic reference
|
// pre-declare to avoid cyclic reference
|
||||||
var recurse func(ma GU, idx int) GU
|
var recurse func(ma GU, idx int) GU
|
||||||
|
|
||||||
|
|||||||
15
v2/iterator/stateless/generic/types.go
Normal file
15
v2/iterator/stateless/generic/types.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package generic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/IBM/fp-go/v2/lazy"
|
||||||
|
"github.com/IBM/fp-go/v2/option"
|
||||||
|
"github.com/IBM/fp-go/v2/pair"
|
||||||
|
"github.com/IBM/fp-go/v2/predicate"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Option[A any] = option.Option[A]
|
||||||
|
Lazy[A any] = lazy.Lazy[A]
|
||||||
|
Pair[L, R any] = pair.Pair[L, R]
|
||||||
|
Predicate[A any] = predicate.Predicate[A]
|
||||||
|
)
|
||||||
@@ -31,14 +31,14 @@ func addToMap[A comparable](a A, m map[A]bool) map[A]bool {
|
|||||||
return cpy
|
return cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
func Uniq[AS ~func() O.Option[P.Pair[AS, A]], K comparable, A any](f func(A) K) func(as AS) AS {
|
func Uniq[AS ~func() Option[Pair[AS, A]], K comparable, A any](f func(A) K) func(as AS) AS {
|
||||||
|
|
||||||
var recurse func(as AS, mp map[K]bool) AS
|
var recurse func(as AS, mp map[K]bool) AS
|
||||||
|
|
||||||
recurse = func(as AS, mp map[K]bool) AS {
|
recurse = func(as AS, mp map[K]bool) AS {
|
||||||
return F.Nullary2(
|
return F.Nullary2(
|
||||||
as,
|
as,
|
||||||
O.Chain(func(a P.Pair[AS, A]) O.Option[P.Pair[AS, A]] {
|
O.Chain(func(a Pair[AS, A]) Option[Pair[AS, A]] {
|
||||||
return F.Pipe3(
|
return F.Pipe3(
|
||||||
P.Tail(a),
|
P.Tail(a),
|
||||||
f,
|
f,
|
||||||
@@ -46,7 +46,7 @@ func Uniq[AS ~func() O.Option[P.Pair[AS, A]], K comparable, A any](f func(A) K)
|
|||||||
_, ok := mp[k]
|
_, ok := mp[k]
|
||||||
return !ok
|
return !ok
|
||||||
}),
|
}),
|
||||||
O.Fold(recurse(P.Head(a), mp), func(k K) O.Option[P.Pair[AS, A]] {
|
O.Fold(recurse(P.Head(a), mp), func(k K) Option[Pair[AS, A]] {
|
||||||
return O.Of(P.MakePair(recurse(P.Head(a), addToMap(k, mp)), P.Tail(a)))
|
return O.Of(P.MakePair(recurse(P.Head(a), addToMap(k, mp)), P.Tail(a)))
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@@ -57,6 +57,6 @@ func Uniq[AS ~func() O.Option[P.Pair[AS, A]], K comparable, A any](f func(A) K)
|
|||||||
return F.Bind2nd(recurse, make(map[K]bool, 0))
|
return F.Bind2nd(recurse, make(map[K]bool, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func StrictUniq[AS ~func() O.Option[P.Pair[AS, A]], A comparable](as AS) AS {
|
func StrictUniq[AS ~func() Option[Pair[AS, A]], A comparable](as AS) AS {
|
||||||
return Uniq[AS](F.Identity[A])(as)
|
return Uniq[AS](F.Identity[A])(as)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ import (
|
|||||||
|
|
||||||
// ZipWith applies a function to pairs of elements at the same index in two iterators, collecting the results in a new iterator. If one
|
// ZipWith applies a function to pairs of elements at the same index in two iterators, collecting the results in a new iterator. If one
|
||||||
// input iterator is short, excess elements of the longer iterator are discarded.
|
// input iterator is short, excess elements of the longer iterator are discarded.
|
||||||
func ZipWith[AS ~func() O.Option[P.Pair[AS, A]], BS ~func() O.Option[P.Pair[BS, B]], CS ~func() O.Option[P.Pair[CS, C]], FCT ~func(A, B) C, A, B, C any](fa AS, fb BS, f FCT) CS {
|
func ZipWith[AS ~func() Option[Pair[AS, A]], BS ~func() Option[Pair[BS, B]], CS ~func() Option[Pair[CS, C]], FCT ~func(A, B) C, A, B, C any](fa AS, fb BS, f FCT) CS {
|
||||||
// pre-declare to avoid cyclic reference
|
// pre-declare to avoid cyclic reference
|
||||||
var m func(P.Pair[O.Option[P.Pair[AS, A]], O.Option[P.Pair[BS, B]]]) O.Option[P.Pair[CS, C]]
|
var m func(Pair[Option[Pair[AS, A]], Option[Pair[BS, B]]]) Option[Pair[CS, C]]
|
||||||
|
|
||||||
recurse := func(as AS, bs BS) CS {
|
recurse := func(as AS, bs BS) CS {
|
||||||
return func() O.Option[P.Pair[CS, C]] {
|
return func() Option[Pair[CS, C]] {
|
||||||
// combine
|
// combine
|
||||||
return F.Pipe1(
|
return F.Pipe1(
|
||||||
P.MakePair(as(), bs()),
|
P.MakePair(as(), bs()),
|
||||||
@@ -38,8 +38,8 @@ func ZipWith[AS ~func() O.Option[P.Pair[AS, A]], BS ~func() O.Option[P.Pair[BS,
|
|||||||
}
|
}
|
||||||
|
|
||||||
m = F.Flow2(
|
m = F.Flow2(
|
||||||
O.SequencePair[P.Pair[AS, A], P.Pair[BS, B]],
|
O.SequencePair[Pair[AS, A], Pair[BS, B]],
|
||||||
O.Map(func(t P.Pair[P.Pair[AS, A], P.Pair[BS, B]]) P.Pair[CS, C] {
|
O.Map(func(t Pair[Pair[AS, A], Pair[BS, B]]) Pair[CS, C] {
|
||||||
return P.MakePair(recurse(P.Head(P.Head(t)), P.Head(P.Tail(t))), f(P.Tail(P.Head(t)), P.Tail(P.Tail(t))))
|
return P.MakePair(recurse(P.Head(P.Head(t)), P.Head(P.Tail(t))), f(P.Tail(P.Head(t)), P.Tail(P.Tail(t))))
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@@ -49,6 +49,6 @@ func ZipWith[AS ~func() O.Option[P.Pair[AS, A]], BS ~func() O.Option[P.Pair[BS,
|
|||||||
|
|
||||||
// Zip takes two iterators and returns an iterators of corresponding pairs. If one input iterators is short, excess elements of the
|
// Zip takes two iterators and returns an iterators of corresponding pairs. If one input iterators is short, excess elements of the
|
||||||
// longer iterator are discarded
|
// longer iterator are discarded
|
||||||
func Zip[AS ~func() O.Option[P.Pair[AS, A]], BS ~func() O.Option[P.Pair[BS, B]], CS ~func() O.Option[P.Pair[CS, P.Pair[A, B]]], A, B any](fb BS) func(AS) CS {
|
func Zip[AS ~func() Option[Pair[AS, A]], BS ~func() Option[Pair[BS, B]], CS ~func() Option[Pair[CS, Pair[A, B]]], A, B any](fb BS) func(AS) CS {
|
||||||
return F.Bind23of3(ZipWith[AS, BS, CS, func(A, B) P.Pair[A, B]])(fb, P.MakePair[A, B])
|
return F.Bind23of3(ZipWith[AS, BS, CS, func(A, B) Pair[A, B]])(fb, P.MakePair[A, B])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,17 +16,15 @@
|
|||||||
package stateless
|
package stateless
|
||||||
|
|
||||||
import (
|
import (
|
||||||
IO "github.com/IBM/fp-go/v2/io"
|
|
||||||
G "github.com/IBM/fp-go/v2/iterator/stateless/generic"
|
G "github.com/IBM/fp-go/v2/iterator/stateless/generic"
|
||||||
L "github.com/IBM/fp-go/v2/lazy"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// FromLazy returns an [Iterator] on top of a lazy function
|
// FromLazy returns an [Iterator] on top of a lazy function
|
||||||
func FromLazy[U any](l L.Lazy[U]) Iterator[U] {
|
func FromLazy[U any](l Lazy[U]) Iterator[U] {
|
||||||
return G.FromLazy[Iterator[U]](l)
|
return G.FromLazy[Iterator[U]](l)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromIO returns an [Iterator] on top of an IO function
|
// FromIO returns an [Iterator] on top of an IO function
|
||||||
func FromIO[U any](io IO.IO[U]) Iterator[U] {
|
func FromIO[U any](io IO[U]) Iterator[U] {
|
||||||
return G.FromLazy[Iterator[U]](io)
|
return G.FromLazy[Iterator[U]](io)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,23 +19,22 @@ import (
|
|||||||
"github.com/IBM/fp-go/v2/iooption"
|
"github.com/IBM/fp-go/v2/iooption"
|
||||||
G "github.com/IBM/fp-go/v2/iterator/stateless/generic"
|
G "github.com/IBM/fp-go/v2/iterator/stateless/generic"
|
||||||
M "github.com/IBM/fp-go/v2/monoid"
|
M "github.com/IBM/fp-go/v2/monoid"
|
||||||
O "github.com/IBM/fp-go/v2/option"
|
|
||||||
"github.com/IBM/fp-go/v2/pair"
|
"github.com/IBM/fp-go/v2/pair"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Next returns the [Iterator] for the next element in an iterator [pair.Pair]
|
// Next returns the [Iterator] for the next element in an iterator [Pair]
|
||||||
func Next[U any](m pair.Pair[Iterator[U], U]) Iterator[U] {
|
func Next[U any](m Pair[Iterator[U], U]) Iterator[U] {
|
||||||
return pair.Head(m)
|
return pair.Head(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current returns the current element in an [Iterator] [pair.Pair]
|
// Current returns the current element in an [Iterator] [Pair]
|
||||||
func Current[U any](m pair.Pair[Iterator[U], U]) U {
|
func Current[U any](m Pair[Iterator[U], U]) U {
|
||||||
return pair.Tail(m)
|
return pair.Tail(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty returns the empty iterator
|
// Empty returns the empty iterator
|
||||||
func Empty[U any]() Iterator[U] {
|
func Empty[U any]() Iterator[U] {
|
||||||
return iooption.None[pair.Pair[Iterator[U], U]]()
|
return iooption.None[Pair[Iterator[U], U]]()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Of returns an iterator with one single element
|
// Of returns an iterator with one single element
|
||||||
@@ -97,12 +96,12 @@ func Replicate[U any](a U) Iterator[U] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FilterMap filters and transforms the content of an iterator
|
// FilterMap filters and transforms the content of an iterator
|
||||||
func FilterMap[U, V any](f func(U) O.Option[V]) Operator[U, V] {
|
func FilterMap[U, V any](f func(U) Option[V]) Operator[U, V] {
|
||||||
return G.FilterMap[Iterator[V], Iterator[U]](f)
|
return G.FilterMap[Iterator[V], Iterator[U]](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter filters the content of an iterator
|
// Filter filters the content of an iterator
|
||||||
func Filter[U any](f func(U) bool) Operator[U, U] {
|
func Filter[U any](f Predicate[U]) Operator[U, U] {
|
||||||
return G.Filter[Iterator[U]](f)
|
return G.Filter[Iterator[U]](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +127,7 @@ func Count(start int) Iterator[int] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FilterChain filters and transforms the content of an iterator
|
// FilterChain filters and transforms the content of an iterator
|
||||||
func FilterChain[U, V any](f func(U) O.Option[Iterator[V]]) Operator[U, V] {
|
func FilterChain[U, V any](f func(U) Option[Iterator[V]]) Operator[U, V] {
|
||||||
return G.FilterChain[Iterator[Iterator[V]], Iterator[V], Iterator[U]](f)
|
return G.FilterChain[Iterator[Iterator[V]], Iterator[V], Iterator[U]](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,10 @@ package stateless
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
G "github.com/IBM/fp-go/v2/iterator/stateless/generic"
|
G "github.com/IBM/fp-go/v2/iterator/stateless/generic"
|
||||||
O "github.com/IBM/fp-go/v2/option"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Last returns the last item in an iterator if such an item exists
|
// Last returns the last item in an iterator if such an item exists
|
||||||
// Note that the function will consume the [Iterator] in this call completely, to identify the last element. Do not use this for infinite iterators
|
// Note that the function will consume the [Iterator] in this call completely, to identify the last element. Do not use this for infinite iterators
|
||||||
func Last[U any](mu Iterator[U]) O.Option[U] {
|
func Last[U any](mu Iterator[U]) Option[U] {
|
||||||
return G.Last(mu)
|
return G.Last(mu)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,6 @@ import (
|
|||||||
// Scan takes an [Iterator] and returns a new [Iterator] of the same length, where the values
|
// Scan takes an [Iterator] and returns a new [Iterator] of the same length, where the values
|
||||||
// of the new [Iterator] are the result of the application of `f` to the value of the
|
// of the new [Iterator] are the result of the application of `f` to the value of the
|
||||||
// source iterator with the previously accumulated value
|
// source iterator with the previously accumulated value
|
||||||
func Scan[FCT ~func(V, U) V, U, V any](f FCT, initial V) func(ma Iterator[U]) Iterator[V] {
|
func Scan[FCT ~func(V, U) V, U, V any](f FCT, initial V) Operator[U, V] {
|
||||||
return G.Scan[Iterator[V], Iterator[U]](f, initial)
|
return G.Scan[Iterator[V], Iterator[U]](f, initial)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func TestScan(t *testing.T) {
|
|||||||
|
|
||||||
dst := F.Pipe1(
|
dst := F.Pipe1(
|
||||||
src,
|
src,
|
||||||
Scan(func(cur P.Pair[int, string], val string) P.Pair[int, string] {
|
Scan(func(cur Pair[int, string], val string) Pair[int, string] {
|
||||||
return P.MakePair(P.Head(cur)+1, val)
|
return P.MakePair(P.Head(cur)+1, val)
|
||||||
}, P.MakePair(0, "")),
|
}, P.MakePair(0, "")),
|
||||||
)
|
)
|
||||||
|
|||||||
29
v2/iterator/stateless/seq.go
Normal file
29
v2/iterator/stateless/seq.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package stateless
|
||||||
|
|
||||||
|
import (
|
||||||
|
O "github.com/IBM/fp-go/v2/option"
|
||||||
|
P "github.com/IBM/fp-go/v2/pair"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ToSeq converts the stateless [Iterator] to an idiomatic go iterator
|
||||||
|
func ToSeq[T any](it Iterator[T]) Seq[T] {
|
||||||
|
current := Current[T]
|
||||||
|
return func(yield Predicate[T]) {
|
||||||
|
next, ok := O.Unwrap(it())
|
||||||
|
for ok && yield(current(next)) {
|
||||||
|
next, ok = O.Unwrap(Next(next)())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToSeq2 converts the stateless [Iterator] to an idiomatic go iterator
|
||||||
|
func ToSeq2[K, V any](it Iterator[Pair[K, V]]) Seq2[K, V] {
|
||||||
|
current := Current[Pair[K, V]]
|
||||||
|
return func(yield func(K, V) bool) {
|
||||||
|
yp := P.Paired(yield)
|
||||||
|
next, ok := O.Unwrap(it())
|
||||||
|
for ok && yp(current(next)) {
|
||||||
|
next, ok = O.Unwrap(Next(next)())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Take limits the number of values in the [Iterator] to a maximum number
|
// Take limits the number of values in the [Iterator] to a maximum number
|
||||||
func Take[U any](n int) func(ma Iterator[U]) Iterator[U] {
|
func Take[U any](n int) Operator[U, U] {
|
||||||
return G.Take[Iterator[U]](n)
|
return G.Take[Iterator[U]](n)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,18 +16,29 @@
|
|||||||
package stateless
|
package stateless
|
||||||
|
|
||||||
import (
|
import (
|
||||||
L "github.com/IBM/fp-go/v2/lazy"
|
"iter"
|
||||||
|
|
||||||
|
"github.com/IBM/fp-go/v2/io"
|
||||||
|
"github.com/IBM/fp-go/v2/lazy"
|
||||||
"github.com/IBM/fp-go/v2/option"
|
"github.com/IBM/fp-go/v2/option"
|
||||||
"github.com/IBM/fp-go/v2/pair"
|
"github.com/IBM/fp-go/v2/pair"
|
||||||
|
"github.com/IBM/fp-go/v2/predicate"
|
||||||
"github.com/IBM/fp-go/v2/reader"
|
"github.com/IBM/fp-go/v2/reader"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
Option[A any] = option.Option[A]
|
Option[A any] = option.Option[A]
|
||||||
|
Lazy[A any] = lazy.Lazy[A]
|
||||||
|
Pair[L, R any] = pair.Pair[L, R]
|
||||||
|
Predicate[A any] = predicate.Predicate[A]
|
||||||
|
IO[A any] = io.IO[A]
|
||||||
|
|
||||||
// Iterator represents a stateless, pure way to iterate over a sequence
|
// Iterator represents a stateless, pure way to iterate over a sequence
|
||||||
Iterator[U any] L.Lazy[Option[pair.Pair[Iterator[U], U]]]
|
Iterator[U any] Lazy[Option[Pair[Iterator[U], U]]]
|
||||||
|
|
||||||
Kleisli[A, B any] = reader.Reader[A, Iterator[B]]
|
Kleisli[A, B any] = reader.Reader[A, Iterator[B]]
|
||||||
Operator[A, B any] = Kleisli[Iterator[A], B]
|
Operator[A, B any] = Kleisli[Iterator[A], B]
|
||||||
|
|
||||||
|
Seq[T any] = iter.Seq[T]
|
||||||
|
Seq2[K, V any] = iter.Seq2[K, V]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -27,6 +27,6 @@ func StrictUniq[A comparable](as Iterator[A]) Iterator[A] {
|
|||||||
|
|
||||||
// Uniq converts an [Iterator] of arbitrary items into an [Iterator] or unique items
|
// Uniq converts an [Iterator] of arbitrary items into an [Iterator] or unique items
|
||||||
// where uniqueness is determined based on a key extractor function
|
// where uniqueness is determined based on a key extractor function
|
||||||
func Uniq[A any, K comparable](f func(A) K) func(as Iterator[A]) Iterator[A] {
|
func Uniq[A any, K comparable](f func(A) K) Operator[A, A] {
|
||||||
return G.Uniq[Iterator[A]](f)
|
return G.Uniq[Iterator[A]](f)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package stateless
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
G "github.com/IBM/fp-go/v2/iterator/stateless/generic"
|
G "github.com/IBM/fp-go/v2/iterator/stateless/generic"
|
||||||
P "github.com/IBM/fp-go/v2/pair"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ZipWith applies a function to pairs of elements at the same index in two iterators, collecting the results in a new iterator. If one
|
// ZipWith applies a function to pairs of elements at the same index in two iterators, collecting the results in a new iterator. If one
|
||||||
@@ -28,6 +27,6 @@ func ZipWith[FCT ~func(A, B) C, A, B, C any](fa Iterator[A], fb Iterator[B], f F
|
|||||||
|
|
||||||
// Zip takes two iterators and returns an iterators of corresponding pairs. If one input iterators is short, excess elements of the
|
// Zip takes two iterators and returns an iterators of corresponding pairs. If one input iterators is short, excess elements of the
|
||||||
// longer iterator are discarded
|
// longer iterator are discarded
|
||||||
func Zip[A, B any](fb Iterator[B]) func(Iterator[A]) Iterator[P.Pair[A, B]] {
|
func Zip[A, B any](fb Iterator[B]) Operator[A, Pair[A, B]] {
|
||||||
return G.Zip[Iterator[A], Iterator[B], Iterator[P.Pair[A, B]]](fb)
|
return G.Zip[Iterator[A], Iterator[B], Iterator[Pair[A, B]]](fb)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ func setCopyCurried[SET ~func(A) Endomorphism[*S], S, A any](setter SET) func(A)
|
|||||||
// name := nameLens.Get(person) // "Alice"
|
// name := nameLens.Get(person) // "Alice"
|
||||||
// updated := nameLens.Set("Bob")(person) // Person{Name: "Bob", Age: 30}
|
// updated := nameLens.Set("Bob")(person) // Person{Name: "Bob", Age: 30}
|
||||||
func MakeLens[GET ~func(S) A, SET ~func(S, A) S, S, A any](get GET, set SET) Lens[S, A] {
|
func MakeLens[GET ~func(S) A, SET ~func(S, A) S, S, A any](get GET, set SET) Lens[S, A] {
|
||||||
return MakeLensCurried(get, F.Curry2(F.Swap(set)))
|
return MakeLensCurried(get, F.Bind2of2(set))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeLensCurried creates a [Lens] with a curried setter F.
|
// MakeLensCurried creates a [Lens] with a curried setter F.
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func setCopy[SET ~func(*S, A) *S, S, A any](setter SET) func(s *S, a A) *S {
|
|||||||
// data. This happens automatically if the data is passed by value. For pointers consider to use `MakeOptionalRef`
|
// data. This happens automatically if the data is passed by value. For pointers consider to use `MakeOptionalRef`
|
||||||
// and for other kinds of data structures that are copied by reference make sure the setter creates the copy.
|
// and for other kinds of data structures that are copied by reference make sure the setter creates the copy.
|
||||||
func MakeOptional[S, A any](get func(S) O.Option[A], set func(S, A) S) Optional[S, A] {
|
func MakeOptional[S, A any](get func(S) O.Option[A], set func(S, A) S) Optional[S, A] {
|
||||||
return Optional[S, A]{GetOption: get, Set: EM.Curry2(F.Swap(set))}
|
return Optional[S, A]{GetOption: get, Set: F.Bind2of2(set)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeOptionalRef creates an Optional based on a getter and a setter function. The setter passed in does not have to create a shallow
|
// MakeOptionalRef creates an Optional based on a getter and a setter function. The setter passed in does not have to create a shallow
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ func Example_immutability_struct() {
|
|||||||
p1 := MakePerson("Carsten", 53)
|
p1 := MakePerson("Carsten", 53)
|
||||||
|
|
||||||
// func(int) func(Person) Person
|
// func(int) func(Person) Person
|
||||||
setAge := F.Curry2(F.Swap(Person.SetAge))
|
setAge := F.Bind2of2(Person.SetAge)
|
||||||
|
|
||||||
p2 := F.Pipe1(
|
p2 := F.Pipe1(
|
||||||
p1,
|
p1,
|
||||||
|
|||||||
@@ -40,10 +40,10 @@ var (
|
|||||||
Equals = F.Curry2(Eq)
|
Equals = F.Curry2(Eq)
|
||||||
|
|
||||||
// Includes returns a predicate that tests for the existence of the search string
|
// Includes returns a predicate that tests for the existence of the search string
|
||||||
Includes = F.Curry2(F.Swap(strings.Contains))
|
Includes = F.Bind2of2(strings.Contains)
|
||||||
|
|
||||||
// HasPrefix returns a predicate that checks if the prefis is included in the string
|
// HasPrefix returns a predicate that checks if the prefis is included in the string
|
||||||
HasPrefix = F.Curry2(F.Swap(strings.HasPrefix))
|
HasPrefix = F.Bind2of2(strings.HasPrefix)
|
||||||
)
|
)
|
||||||
|
|
||||||
func Eq(left string, right string) bool {
|
func Eq(left string, right string) bool {
|
||||||
|
|||||||
Reference in New Issue
Block a user