diff --git a/v2/array/array.go b/v2/array/array.go index b11c015..c8b55bd 100644 --- a/v2/array/array.go +++ b/v2/array/array.go @@ -260,6 +260,8 @@ func Empty[A any]() []A { } // Zero returns an empty array of type A (alias for Empty). +// +//go:inline func Zero[A any]() []A { return Empty[A]() } diff --git a/v2/array/generic/array.go b/v2/array/generic/array.go index d210dd6..88b9571 100644 --- a/v2/array/generic/array.go +++ b/v2/array/generic/array.go @@ -25,8 +25,10 @@ import ( ) // Of constructs a single element array +// +//go:inline func Of[GA ~[]A, A any](value A) GA { - return GA{value} + return array.Of[GA](value) } func Reduce[GA ~[]A, A, B any](f func(B, A) B, initial B) func(GA) B { diff --git a/v2/array/generic/monoid.go b/v2/array/generic/monoid.go new file mode 100644 index 0000000..1ac6d35 --- /dev/null +++ b/v2/array/generic/monoid.go @@ -0,0 +1,34 @@ +package generic + +import ( + "github.com/IBM/fp-go/v2/internal/array" + M "github.com/IBM/fp-go/v2/monoid" + S "github.com/IBM/fp-go/v2/semigroup" +) + +// Monoid returns a Monoid instance for arrays. +// The Monoid combines arrays through concatenation, with an empty array as the identity element. +// +// Example: +// +// m := array.Monoid[int]() +// result := m.Concat([]int{1, 2}, []int{3, 4}) // [1, 2, 3, 4] +// empty := m.Empty() // [] +// +//go:inline +func Monoid[GT ~[]T, T any]() M.Monoid[GT] { + return M.MakeMonoid(array.Concat[GT], Empty[GT]()) +} + +// Semigroup returns a Semigroup instance for arrays. +// The Semigroup combines arrays through concatenation. +// +// Example: +// +// s := array.Semigroup[int]() +// result := s.Concat([]int{1, 2}, []int{3, 4}) // [1, 2, 3, 4] +// +//go:inline +func Semigroup[GT ~[]T, T any]() S.Semigroup[GT] { + return S.MakeSemigroup(array.Concat[GT]) +} diff --git a/v2/array/misc_test.go b/v2/array/misc_test.go index 114a315..e1c21c9 100644 --- a/v2/array/misc_test.go +++ b/v2/array/misc_test.go @@ -18,7 +18,6 @@ package array import ( "testing" - O "github.com/IBM/fp-go/v2/option" OR "github.com/IBM/fp-go/v2/ord" "github.com/stretchr/testify/assert" ) @@ -103,39 +102,6 @@ func TestSortByKey(t *testing.T) { assert.Equal(t, "Charlie", result[2].Name) } -func TestMonadTraverse(t *testing.T) { - result := MonadTraverse( - O.Of[[]int], - O.Map[[]int, func(int) []int], - O.Ap[[]int, int], - []int{1, 3, 5}, - func(n int) O.Option[int] { - if n%2 == 1 { - return O.Some(n * 2) - } - return O.None[int]() - }, - ) - - assert.Equal(t, O.Some([]int{2, 6, 10}), result) - - // Test with None case - result2 := MonadTraverse( - O.Of[[]int], - O.Map[[]int, func(int) []int], - O.Ap[[]int, int], - []int{1, 2, 3}, - func(n int) O.Option[int] { - if n%2 == 1 { - return O.Some(n * 2) - } - return O.None[int]() - }, - ) - - assert.Equal(t, O.None[[]int](), result2) -} - func TestUniqByKey(t *testing.T) { type Person struct { Name string diff --git a/v2/array/monoid.go b/v2/array/monoid.go index 645cbb6..6de189c 100644 --- a/v2/array/monoid.go +++ b/v2/array/monoid.go @@ -16,27 +16,12 @@ package array import ( + G "github.com/IBM/fp-go/v2/array/generic" "github.com/IBM/fp-go/v2/internal/array" M "github.com/IBM/fp-go/v2/monoid" S "github.com/IBM/fp-go/v2/semigroup" ) -func concat[T any](left, right []T) []T { - // some performance checks - ll := len(left) - if ll == 0 { - return right - } - lr := len(right) - if lr == 0 { - return left - } - // need to copy - buf := make([]T, ll+lr) - copy(buf[copy(buf, left):], right) - return buf -} - // Monoid returns a Monoid instance for arrays. // The Monoid combines arrays through concatenation, with an empty array as the identity element. // @@ -45,8 +30,10 @@ func concat[T any](left, right []T) []T { // m := array.Monoid[int]() // result := m.Concat([]int{1, 2}, []int{3, 4}) // [1, 2, 3, 4] // empty := m.Empty() // [] +// +//go:inline func Monoid[T any]() M.Monoid[[]T] { - return M.MakeMonoid(concat[T], Empty[T]()) + return G.Monoid[[]T]() } // Semigroup returns a Semigroup instance for arrays. @@ -56,8 +43,10 @@ func Monoid[T any]() M.Monoid[[]T] { // // s := array.Semigroup[int]() // result := s.Concat([]int{1, 2}, []int{3, 4}) // [1, 2, 3, 4] +// +//go:inline func Semigroup[T any]() S.Semigroup[[]T] { - return S.MakeSemigroup(concat[T]) + return G.Semigroup[[]T]() } func addLen[A any](count int, data []A) int { diff --git a/v2/array/sequence.go b/v2/array/sequence.go index 5a5d47a..74c6cdb 100644 --- a/v2/array/sequence.go +++ b/v2/array/sequence.go @@ -16,10 +16,18 @@ package array import ( - F "github.com/IBM/fp-go/v2/function" + "github.com/IBM/fp-go/v2/internal/array" + M "github.com/IBM/fp-go/v2/monoid" O "github.com/IBM/fp-go/v2/option" ) +func MonadSequence[HKTA, HKTRA any]( + fof func(HKTA) HKTRA, + m M.Monoid[HKTRA], + ma []HKTA) HKTRA { + return array.MonadSequence(fof, m.Empty(), m.Concat, ma) +} + // Sequence takes an array where elements are HKT (higher kinded type) and, // using an applicative of that HKT, returns an HKT of []A. // @@ -55,16 +63,11 @@ import ( // option.MonadAp[[]int, int], // ) // result := seq(opts) // Some([1, 2, 3]) -func Sequence[A, HKTA, HKTRA, HKTFRA any]( - _of func([]A) HKTRA, - _map func(HKTRA, func([]A) func(A) []A) HKTFRA, - _ap func(HKTFRA, HKTA) HKTRA, +func Sequence[HKTA, HKTRA any]( + fof func(HKTA) HKTRA, + m M.Monoid[HKTRA], ) func([]HKTA) HKTRA { - ca := F.Curry2(Append[A]) - empty := _of(Empty[A]()) - return Reduce(func(fas HKTRA, fa HKTA) HKTRA { - return _ap(_map(fas, ca), fa) - }, empty) + return array.Sequence[[]HKTA](fof, m.Empty(), m.Concat) } // ArrayOption returns a function to convert a sequence of options into an option of a sequence. @@ -86,10 +89,10 @@ func Sequence[A, HKTA, HKTRA, HKTFRA any]( // option.Some(3), // } // result2 := array.ArrayOption[int]()(opts2) // None -func ArrayOption[A any]() func([]Option[A]) Option[[]A] { - return Sequence( - O.Of[[]A], - O.MonadMap[[]A, func(A) []A], - O.MonadAp[[]A, A], +func ArrayOption[A any](ma []Option[A]) Option[[]A] { + return MonadSequence( + O.Map(Of[A]), + O.ApplicativeMonoid(Monoid[A]()), + ma, ) } diff --git a/v2/array/sequence_test.go b/v2/array/sequence_test.go index 432eb39..b4bb25b 100644 --- a/v2/array/sequence_test.go +++ b/v2/array/sequence_test.go @@ -24,8 +24,7 @@ import ( ) func TestSequenceOption(t *testing.T) { - seq := ArrayOption[int]() - assert.Equal(t, O.Of([]int{1, 3}), seq([]O.Option[int]{O.Of(1), O.Of(3)})) - assert.Equal(t, O.None[[]int](), seq([]O.Option[int]{O.Of(1), O.None[int]()})) + assert.Equal(t, O.Of([]int{1, 3}), ArrayOption([]O.Option[int]{O.Of(1), O.Of(3)})) + assert.Equal(t, O.None[[]int](), ArrayOption([]O.Option[int]{O.Of(1), O.None[int]()})) } diff --git a/v2/array/traverse.go b/v2/array/traverse.go index 22a3238..cb0b63a 100644 --- a/v2/array/traverse.go +++ b/v2/array/traverse.go @@ -80,3 +80,25 @@ func MonadTraverse[A, B, HKTB, HKTAB, HKTRB any]( return array.MonadTraverse(fof, fmap, fap, ta, f) } + +//go:inline +func TraverseWithIndex[A, B, HKTB, HKTAB, HKTRB any]( + fof func([]B) HKTRB, + fmap func(func([]B) func(B) []B) func(HKTRB) HKTAB, + fap func(HKTB) func(HKTAB) HKTRB, + + f func(int, A) HKTB) func([]A) HKTRB { + return array.TraverseWithIndex[[]A](fof, fmap, fap, f) +} + +//go:inline +func MonadTraverseWithIndex[A, B, HKTB, HKTAB, HKTRB any]( + fof func([]B) HKTRB, + fmap func(func([]B) func(B) []B) func(HKTRB) HKTAB, + fap func(HKTB) func(HKTAB) HKTRB, + + ta []A, + f func(int, A) HKTB) HKTRB { + + return array.MonadTraverseWithIndex(fof, fmap, fap, ta, f) +} diff --git a/v2/context/readerioresult/reader_test.go b/v2/context/readerioresult/reader_test.go index cfdbd12..6b50b1e 100644 --- a/v2/context/readerioresult/reader_test.go +++ b/v2/context/readerioresult/reader_test.go @@ -312,7 +312,7 @@ func TestMonadChainFirstLeft(t *testing.T) { Left[int](originalErr), func(e error) ReaderIOResult[int] { capturedError = e - return Right[int](999) // This Right value is ignored + return Right(999) // This Right value is ignored }, ) actualResult := result(ctx)() @@ -324,7 +324,7 @@ func TestMonadChainFirstLeft(t *testing.T) { t.Run("Right value passes through", func(t *testing.T) { sideEffectCalled := false result := MonadChainFirstLeft( - Right[int](42), + Right(42), func(e error) ReaderIOResult[int] { sideEffectCalled = true return Left[int](fmt.Errorf("should not be called")) @@ -343,7 +343,7 @@ func TestMonadChainFirstLeft(t *testing.T) { func(e error) ReaderIOResult[int] { effectCount++ // Try to return Right, but original Left should still be returned - return Right[int](999) + return Right(999) }, ) actualResult := result(ctx)() @@ -378,7 +378,7 @@ func TestChainFirstLeft(t *testing.T) { originalErr := fmt.Errorf("test error") chainFn := ChainFirstLeft[int](func(e error) ReaderIOResult[int] { captured = e - return Right[int](42) // This Right is ignored + return Right(42) // This Right is ignored }) result := F.Pipe1( Left[int](originalErr), @@ -394,10 +394,10 @@ func TestChainFirstLeft(t *testing.T) { called := false chainFn := ChainFirstLeft[int](func(e error) ReaderIOResult[int] { called = true - return Right[int](0) + return Right(0) }) result := F.Pipe1( - Right[int](100), + Right(100), chainFn, ) assert.False(t, called) @@ -409,7 +409,7 @@ func TestChainFirstLeft(t *testing.T) { originalErr := fmt.Errorf("original") chainFn := ChainFirstLeft[int](func(e error) ReaderIOResult[int] { // Try to return Right, but original Left should still be returned - return Right[int](999) + return Right(999) }) result := F.Pipe1( diff --git a/v2/context/readerioresult/traverse.go b/v2/context/readerioresult/traverse.go index 1e0a93c..ce3addd 100644 --- a/v2/context/readerioresult/traverse.go +++ b/v2/context/readerioresult/traverse.go @@ -16,8 +16,8 @@ package readerioresult import ( + "github.com/IBM/fp-go/v2/array" "github.com/IBM/fp-go/v2/function" - "github.com/IBM/fp-go/v2/internal/array" "github.com/IBM/fp-go/v2/internal/record" ) @@ -29,7 +29,7 @@ import ( // // Returns a function that transforms an array into a ReaderIOResult of an array. func TraverseArray[A, B any](f Kleisli[A, B]) Kleisli[[]A, []B] { - return array.Traverse[[]A]( + return array.Traverse( Of[[]B], Map[[]B, func(B) []B], Ap[[]B, B], @@ -46,7 +46,7 @@ func TraverseArray[A, B any](f Kleisli[A, B]) Kleisli[[]A, []B] { // // Returns a function that transforms an array into a ReaderIOResult of an array. func TraverseArrayWithIndex[A, B any](f func(int, A) ReaderIOResult[B]) Kleisli[[]A, []B] { - return array.TraverseWithIndex[[]A]( + return array.TraverseWithIndex( Of[[]B], Map[[]B, func(B) []B], Ap[[]B, B], @@ -135,22 +135,20 @@ func MonadTraverseArraySeq[A, B any](as []A, f Kleisli[A, B]) ReaderIOResult[[]B // // Returns a function that transforms an array into a ReaderIOResult of an array. func TraverseArraySeq[A, B any](f Kleisli[A, B]) Kleisli[[]A, []B] { - return array.Traverse[[]A]( + return array.Traverse( Of[[]B], Map[[]B, func(B) []B], ApSeq[[]B, B], - f, ) } // TraverseArrayWithIndexSeq uses transforms an array [[]A] into [[]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[[]B]] func TraverseArrayWithIndexSeq[A, B any](f func(int, A) ReaderIOResult[B]) Kleisli[[]A, []B] { - return array.TraverseWithIndex[[]A]( + return array.TraverseWithIndex( Of[[]B], Map[[]B, func(B) []B], ApSeq[[]B, B], - f, ) } @@ -230,22 +228,20 @@ func MonadTraverseArrayPar[A, B any](as []A, f Kleisli[A, B]) ReaderIOResult[[]B // // Returns a function that transforms an array into a ReaderIOResult of an array. func TraverseArrayPar[A, B any](f Kleisli[A, B]) Kleisli[[]A, []B] { - return array.Traverse[[]A]( + return array.Traverse( Of[[]B], Map[[]B, func(B) []B], ApPar[[]B, B], - f, ) } // TraverseArrayWithIndexPar uses transforms an array [[]A] into [[]ReaderIOResult[B]] and then resolves that into a [ReaderIOResult[[]B]] func TraverseArrayWithIndexPar[A, B any](f func(int, A) ReaderIOResult[B]) Kleisli[[]A, []B] { - return array.TraverseWithIndex[[]A]( + return array.TraverseWithIndex( Of[[]B], Map[[]B, func(B) []B], ApPar[[]B, B], - f, ) } diff --git a/v2/internal/array/array.go b/v2/internal/array/array.go index a454560..6ce68ce 100644 --- a/v2/internal/array/array.go +++ b/v2/internal/array/array.go @@ -15,6 +15,10 @@ package array +func Of[GA ~[]A, A any](a A) GA { + return GA{a} +} + func Slice[GA ~[]A, A any](low, high int) func(as GA) GA { return func(as GA) GA { length := len(as) @@ -140,7 +144,7 @@ func UpsertAt[GA ~[]A, A any](a A) func(GA) GA { func MonadMap[GA ~[]A, GB ~[]B, A, B any](as GA, f func(a A) B) GB { count := len(as) bs := make(GB, count) - for i := count - 1; i >= 0; i-- { + for i := range count { bs[i] = f(as[i]) } return bs @@ -155,7 +159,7 @@ func Map[GA ~[]A, GB ~[]B, A, B any](f func(a A) B) func(GA) GB { func MonadMapWithIndex[GA ~[]A, GB ~[]B, A, B any](as GA, f func(idx int, a A) B) GB { count := len(as) bs := make(GB, count) - for i := count - 1; i >= 0; i-- { + for i := range count { bs[i] = f(i, as[i]) } return bs @@ -164,3 +168,19 @@ func MonadMapWithIndex[GA ~[]A, GB ~[]B, A, B any](as GA, f func(idx int, a A) B func ConstNil[GA ~[]A, A any]() GA { return (GA)(nil) } + +func Concat[GT ~[]T, T any](left, right GT) GT { + // some performance checks + ll := len(left) + if ll == 0 { + return right + } + lr := len(right) + if lr == 0 { + return left + } + // need to copy + buf := make(GT, ll+lr) + copy(buf[copy(buf, left):], right) + return buf +} diff --git a/v2/internal/array/traverse.go b/v2/internal/array/traverse.go index 5eba0da..07d304c 100644 --- a/v2/internal/array/traverse.go +++ b/v2/internal/array/traverse.go @@ -19,6 +19,72 @@ import ( F "github.com/IBM/fp-go/v2/function" ) +func MonadSequenceSegment[HKTB, HKTRB any]( + fof func(HKTB) HKTRB, + empty HKTRB, + concat func(HKTRB, HKTRB) HKTRB, + fbs []HKTB, + start, end int, +) HKTRB { + + switch end - start { + case 0: + return empty + case 1: + return fof(fbs[start]) + default: + mid := (start + end) / 2 + return concat( + MonadSequenceSegment(fof, empty, concat, fbs, start, mid), + MonadSequenceSegment(fof, empty, concat, fbs, mid, end), + ) + } +} + +func SequenceSegment[HKTB, HKTRB any]( + fof func(HKTB) HKTRB, + empty HKTRB, + concat func(HKTRB, HKTRB) HKTRB, +) func([]HKTB) HKTRB { + + concat_f := func(left, right func([]HKTB) HKTRB) func([]HKTB) HKTRB { + return func(fbs []HKTB) HKTRB { + return concat(left(fbs), right(fbs)) + } + } + empty_f := F.Constant1[[]HKTB](empty) + at := func(idx int) func([]HKTB) HKTRB { + return func(fbs []HKTB) HKTRB { + return fof(fbs[idx]) + } + } + + var divide func(start, end int) func([]HKTB) HKTRB + divide = func(start, end int) func([]HKTB) HKTRB { + switch end - start { + case 0: + return empty_f + case 1: + return at(start) + default: + mid := (start + end) / 2 + left := divide(start, mid) + right := divide(mid, end) + + return concat_f(left, right) + } + } + + // TODO this could be cached by length + get_divide := func(len int) func([]HKTB) HKTRB { + return divide(0, len) + } + + return func(fbs []HKTB) HKTRB { + return get_divide(len(fbs))(fbs) + } +} + /* * We need to pass the members of the applicative explicitly, because golang does neither support higher kinded types nor template methods on structs or interfaces @@ -79,6 +145,34 @@ func TraverseWithIndex[GA ~[]A, GB ~[]B, A, B, HKTB, HKTAB, HKTRB any]( } } +/* +* +We need to pass the members of the applicative explicitly, because golang does neither support higher kinded types nor template methods on structs or interfaces + +HKTRB = HKT +HKTB = HKT +HKTAB = HKT +*/ +func MonadSequence[GA ~[]HKTA, HKTA, HKTRA any]( + fof func(HKTA) HKTRA, + empty HKTRA, + concat func(HKTRA, HKTRA) HKTRA, + + ta GA) HKTRA { + return MonadSequenceSegment(fof, empty, concat, ta, 0, len(ta)) +} + +func Sequence[GA ~[]HKTA, HKTA, HKTRA any]( + fof func(HKTA) HKTRA, + empty HKTRA, + concat func(HKTRA, HKTRA) HKTRA, +) func(GA) HKTRA { + + return func(ma GA) HKTRA { + return MonadSequence(fof, empty, concat, ma) + } +} + func MonadTraverseReduce[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any]( fof func(GB) HKTRB, fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB, diff --git a/v2/internal/iter/iter.go b/v2/internal/iter/iter.go index 3993770..fecfb3e 100644 --- a/v2/internal/iter/iter.go +++ b/v2/internal/iter/iter.go @@ -2,6 +2,7 @@ package iter import ( F "github.com/IBM/fp-go/v2/function" + M "github.com/IBM/fp-go/v2/monoid" ) func MonadReduceWithIndex[GA ~func(yield func(A) bool), A, B any](fa GA, f func(int, B, A) B, initial B) B { @@ -59,3 +60,41 @@ func Prepend[GA ~func(yield func(A) bool), A any](head A) func(GA) GA { func Empty[GA ~func(yield func(A) bool), A any]() GA { return func(_ func(A) bool) {} } + +func ToArray[GA ~func(yield func(A) bool), GB ~[]A, A any](fa GA) GB { + bs := make(GB, 0) + for a := range fa { + bs = append(bs, a) + } + return bs +} + +func MonadMapToArray[GA ~func(yield func(A) bool), GB ~[]B, A, B any](fa GA, f func(A) B) GB { + bs := make(GB, 0) + for a := range fa { + bs = append(bs, f(a)) + } + return bs +} + +func MapToArray[GA ~func(yield func(A) bool), GB ~[]B, A, B any](f func(A) B) func(GA) GB { + return F.Bind2nd(MonadMapToArray[GA, GB], f) +} + +func MonadMapToArrayWithIndex[GA ~func(yield func(A) bool), GB ~[]B, A, B any](fa GA, f func(int, A) B) GB { + bs := make(GB, 0) + var i int + for a := range fa { + bs = append(bs, f(i, a)) + i += 1 + } + return bs +} + +func MapToArrayWithIndex[GA ~func(yield func(A) bool), GB ~[]B, A, B any](f func(int, A) B) func(GA) GB { + return F.Bind2nd(MonadMapToArrayWithIndex[GA, GB], f) +} + +func Monoid[GA ~func(yield func(A) bool), A any]() M.Monoid[GA] { + return M.MakeMonoid(Concat[GA], Empty[GA]()) +} diff --git a/v2/internal/iter/traverse.go b/v2/internal/iter/traverse.go index a8b1333..44bb226 100644 --- a/v2/internal/iter/traverse.go +++ b/v2/internal/iter/traverse.go @@ -17,6 +17,8 @@ package iter import ( F "github.com/IBM/fp-go/v2/function" + INTA "github.com/IBM/fp-go/v2/internal/array" + M "github.com/IBM/fp-go/v2/monoid" ) /* @@ -27,14 +29,65 @@ HKTRB = HKT HKTB = HKT HKTAB = HKT */ -func MonadTraverse[GA ~func(yield func(A) bool), GB ~func(yield func(B) bool), A, B, HKTB, HKTAB, HKTRB any]( - fof func(GB) HKTRB, - fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB, - fap func(HKTB) func(HKTAB) HKTRB, +func MonadTraverse[GA ~func(yield func(A) bool), GB ~func(yield func(B) bool), A, B, HKT_B, HKT_GB_GB, HKT_GB any]( + fmap_b func(HKT_B, func(B) GB) HKT_GB, + + fof_gb func(GB) HKT_GB, + fmap_gb func(HKT_GB, func(GB) func(GB) GB) HKT_GB_GB, + fap_gb func(HKT_GB_GB, HKT_GB) HKT_GB, ta GA, - f func(A) HKTB) HKTRB { - return MonadTraverseReduce(fof, fmap, fap, ta, f, MonadAppend[GB, B], Empty[GB]()) + f func(A) HKT_B) HKT_GB { + + fof := F.Bind2nd(fmap_b, Of[GB]) + + empty := fof_gb(Empty[GB]()) + + cb := F.Curry2(Concat[GB]) + concat_gb := F.Bind2nd(fmap_gb, cb) + concat := func(first HKT_GB, second HKT_GB) HKT_GB { + return fap_gb(concat_gb(first), second) + } + + // convert to an array + hktb := MonadMapToArray[GA, []HKT_B](ta, f) + return INTA.MonadSequenceSegment(fof, empty, concat, hktb, 0, len(hktb)) +} + +func Traverse[GA ~func(yield func(A) bool), GB ~func(yield func(B) bool), A, B, HKT_B, HKT_GB_GB, HKT_GB any]( + fmap_b func(func(B) GB) func(HKT_B) HKT_GB, + + fof_gb func(GB) HKT_GB, + fmap_gb func(func(GB) func(GB) GB) func(HKT_GB) HKT_GB_GB, + fap_gb func(HKT_GB_GB, HKT_GB) HKT_GB, + + f func(A) HKT_B) func(GA) HKT_GB { + + fof := fmap_b(Of[GB]) + empty := fof_gb(Empty[GB]()) + cb := F.Curry2(Concat[GB]) + concat_gb := fmap_gb(cb) + + concat := func(first, second HKT_GB) HKT_GB { + return fap_gb(concat_gb(first), second) + } + + return func(ma GA) HKT_GB { + // return INTA.SequenceSegment(fof, empty, concat)(MapToArray[GA, []HKT_B](f)(ma)) + hktb := MonadMapToArray[GA, []HKT_B](ma, f) + return INTA.MonadSequenceSegment(fof, empty, concat, hktb, 0, len(hktb)) + } +} + +func MonadSequence[GA ~func(yield func(HKTA) bool), HKTA, HKTRA any]( + fof func(HKTA) HKTRA, + m M.Monoid[HKTRA], + + ta GA) HKTRA { + + // convert to an array + hktb := ToArray[GA, []HKTA](ta) + return INTA.MonadSequenceSegment(fof, m.Empty(), m.Concat, hktb, 0, len(hktb)) } /* @@ -45,37 +98,35 @@ HKTRB = HKT HKTB = HKT HKTAB = HKT */ -func MonadTraverseWithIndex[GA ~func(yield func(A) bool), GB ~func(yield func(B) bool), A, B, HKTB, HKTAB, HKTRB any]( - fof func(GB) HKTRB, - fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB, - fap func(HKTB) func(HKTAB) HKTRB, +func MonadTraverseWithIndex[GA ~func(yield func(A) bool), A, HKTB, HKTRB any]( + fof func(HKTB) HKTRB, + m M.Monoid[HKTRB], ta GA, f func(int, A) HKTB) HKTRB { - return MonadTraverseReduceWithIndex(fof, fmap, fap, ta, f, MonadAppend[GB, B], Empty[GB]()) + + // convert to an array + hktb := MonadMapToArrayWithIndex[GA, []HKTB](ta, f) + return INTA.MonadSequenceSegment(fof, m.Empty(), m.Concat, hktb, 0, len(hktb)) } -func Traverse[GA ~func(yield func(A) bool), GB ~func(yield func(B) bool), A, B, HKTB, HKTAB, HKTRB any]( - fof func(GB) HKTRB, - fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB, - fap func(HKTB) func(HKTAB) HKTRB, +func Sequence[GA ~func(yield func(HKTA) bool), HKTA, HKTRA any]( + fof func(HKTA) HKTRA, + m M.Monoid[HKTRA]) func(GA) HKTRA { - f func(A) HKTB) func(GA) HKTRB { - - return func(ma GA) HKTRB { - return MonadTraverse(fof, fmap, fap, ma, f) + return func(ma GA) HKTRA { + return MonadSequence(fof, m, ma) } } -func TraverseWithIndex[GA ~func(yield func(A) bool), GB ~func(yield func(B) bool), A, B, HKTB, HKTAB, HKTRB any]( - fof func(GB) HKTRB, - fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB, - fap func(HKTB) func(HKTAB) HKTRB, +func TraverseWithIndex[GA ~func(yield func(A) bool), A, HKTB, HKTRB any]( + fof func(HKTB) HKTRB, + m M.Monoid[HKTRB], f func(int, A) HKTB) func(GA) HKTRB { return func(ma GA) HKTRB { - return MonadTraverseWithIndex(fof, fmap, fap, ma, f) + return MonadTraverseWithIndex(fof, m, ma, f) } } diff --git a/v2/io/traverse.go b/v2/io/traverse.go index a4c49ba..106e676 100644 --- a/v2/io/traverse.go +++ b/v2/io/traverse.go @@ -63,9 +63,11 @@ func TraverseArray[A, B any](f Kleisli[A, B]) Kleisli[[]A, []B] { func TraverseIter[A, B any](f Kleisli[A, B]) Kleisli[Seq[A], Seq[B]] { return INTI.Traverse[Seq[A]]( + Map[B], + Of[Seq[B]], - Map[Seq[B], func(B) Seq[B]], - Ap[Seq[B], B], + Map[Seq[B]], + MonadAp[Seq[B]], f, ) diff --git a/v2/iterator/iter/iter.go b/v2/iterator/iter/iter.go index 422d4ff..a033ece 100644 --- a/v2/iterator/iter/iter.go +++ b/v2/iterator/iter/iter.go @@ -885,3 +885,13 @@ func MonadZip[A, B any](fb Seq[B], fa Seq[A]) Seq2[A, B] { func Zip[A, B any](fa Seq[A]) func(Seq[B]) Seq2[A, B] { return F.Bind2nd(MonadZip[A, B], fa) } + +//go:inline +func MonadMapToArray[A, B any](fa Seq[A], f func(A) B) []B { + return G.MonadMapToArray[Seq[A], []B](fa, f) +} + +//go:inline +func MapToArray[A, B any](f func(A) B) func(Seq[A]) []B { + return G.MapToArray[Seq[A], []B](f) +} diff --git a/v2/iterator/iter/monid.go b/v2/iterator/iter/monoid.go similarity index 95% rename from v2/iterator/iter/monid.go rename to v2/iterator/iter/monoid.go index 1dbc1a1..6ae3aad 100644 --- a/v2/iterator/iter/monid.go +++ b/v2/iterator/iter/monoid.go @@ -33,5 +33,5 @@ import ( // //go:inline func Monoid[T any]() M.Monoid[Seq[T]] { - return M.MakeMonoid(G.Concat[Seq[T]], Empty[T]()) + return G.Monoid[Seq[T]]() } diff --git a/v2/option/apply.go b/v2/option/apply.go index 43946df..f7b410a 100644 --- a/v2/option/apply.go +++ b/v2/option/apply.go @@ -42,6 +42,8 @@ func ApplySemigroup[A any](s S.Semigroup[A]) S.Semigroup[Option[A]] { // optMonoid := ApplicativeMonoid(intMonoid) // result := optMonoid.Concat(Some(2), Some(3)) // Some(5) // result := optMonoid.Empty() // Some(0) +// +//go:inline func ApplicativeMonoid[A any](m M.Monoid[A]) M.Monoid[Option[A]] { return M.ApplicativeMonoid(Of[A], MonadMap[A, func(A) A], MonadAp[A, A], m) } diff --git a/v2/option/iter.go b/v2/option/iter.go index 409dd9d..567ab07 100644 --- a/v2/option/iter.go +++ b/v2/option/iter.go @@ -55,11 +55,22 @@ import ( // result := TraverseIter(parse)(invalidStrings) // // result is None because "invalid" cannot be parsed func TraverseIter[A, B any](f Kleisli[A, B]) Kleisli[Seq[A], Seq[B]] { + return INTI.Traverse[Seq[A]]( + Map[B], + Of[Seq[B]], - Map[Seq[B], func(B) Seq[B]], - Ap[Seq[B]], + Map[Seq[B]], + MonadAp[Seq[B]], f, ) } + +func SequenceIter[A any](as Seq[Option[A]]) Option[Seq[A]] { + return INTI.MonadSequence( + Map(INTI.Of[Seq[A]]), + ApplicativeMonoid(INTI.Monoid[Seq[A]]()), + as, + ) +} diff --git a/v2/reader/array.go b/v2/reader/array.go index 9755aa9..71dbb94 100644 --- a/v2/reader/array.go +++ b/v2/reader/array.go @@ -17,7 +17,7 @@ package reader import ( "github.com/IBM/fp-go/v2/function" - "github.com/IBM/fp-go/v2/internal/array" + G "github.com/IBM/fp-go/v2/reader/generic" ) // MonadTraverseArray transforms each element of an array using a function that returns a Reader, @@ -38,13 +38,7 @@ import ( // r := reader.MonadTraverseArray(numbers, addPrefix) // result := r(Config{Prefix: "num"}) // ["num1", "num2", "num3"] func MonadTraverseArray[R, A, B any](ma []A, f Kleisli[R, A, B]) Reader[R, []B] { - return array.MonadTraverse( - Of[R, []B], - Map[R, []B, func(B) []B], - Ap[[]B, R, B], - ma, - f, - ) + return G.MonadTraverseArray[Reader[R, B], Reader[R, []B], []A](ma, f) } // TraverseArray transforms each element of an array using a function that returns a Reader, @@ -63,12 +57,7 @@ func MonadTraverseArray[R, A, B any](ma []A, f Kleisli[R, A, B]) Reader[R, []B] // r := transform([]int{1, 2, 3}) // result := r(Config{Multiplier: 10}) // [10, 20, 30] func TraverseArray[R, A, B any](f Kleisli[R, A, B]) func([]A) Reader[R, []B] { - return array.Traverse[[]A]( - Of[R, []B], - Map[R, []B, func(B) []B], - Ap[[]B, R, B], - f, - ) + return G.TraverseArray[Reader[R, B], Reader[R, []B], []A](f) } // TraverseArrayWithIndex transforms each element of an array using a function that takes @@ -89,12 +78,7 @@ func TraverseArray[R, A, B any](f Kleisli[R, A, B]) func([]A) Reader[R, []B] { // r := transform([]string{"a", "b", "c"}) // result := r(Config{Prefix: "item"}) // ["item[0]:a", "item[1]:b", "item[2]:c"] func TraverseArrayWithIndex[R, A, B any](f func(int, A) Reader[R, B]) func([]A) Reader[R, []B] { - return array.TraverseWithIndex[[]A]( - Of[R, []B], - Map[R, []B, func(B) []B], - Ap[[]B, R, B], - f, - ) + return G.TraverseArrayWithIndex[Reader[R, B], Reader[R, []B], []A](f) } // SequenceArray converts an array of Readers into a single Reader containing an array. diff --git a/v2/reader/generic/monoid.go b/v2/reader/generic/monoid.go new file mode 100644 index 0000000..e2e2c33 --- /dev/null +++ b/v2/reader/generic/monoid.go @@ -0,0 +1,15 @@ +package generic + +import ( + M "github.com/IBM/fp-go/v2/monoid" +) + +//go:inline +func ApplicativeMonoid[GA ~func(R) A, R, A any](m M.Monoid[A]) M.Monoid[GA] { + return M.ApplicativeMonoid( + Of[GA, R, A], + MonadMap[GA, func(R) func(A) A], + MonadAp[GA, GA, func(R) func(A) A], + m, + ) +}