// Copyright (c) 2023 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 generic import ( F "github.com/IBM/fp-go/function" "github.com/IBM/fp-go/internal/array" FC "github.com/IBM/fp-go/internal/functor" M "github.com/IBM/fp-go/monoid" O "github.com/IBM/fp-go/option" "github.com/IBM/fp-go/tuple" ) // Of constructs a single element array func Of[GA ~[]A, A any](value A) GA { return GA{value} } func Reduce[GA ~[]A, A, B any](f func(B, A) B, initial B) func(GA) B { return func(as GA) B { return MonadReduce[GA](as, f, initial) } } func ReduceWithIndex[GA ~[]A, A, B any](f func(int, B, A) B, initial B) func(GA) B { return func(as GA) B { return MonadReduceWithIndex[GA](as, f, initial) } } func ReduceRight[GA ~[]A, A, B any](f func(A, B) B, initial B) func(GA) B { return func(as GA) B { return MonadReduceRight[GA](as, f, initial) } } func ReduceRightWithIndex[GA ~[]A, A, B any](f func(int, A, B) B, initial B) func(GA) B { return func(as GA) B { return MonadReduceRightWithIndex[GA](as, f, initial) } } func MonadReduce[GA ~[]A, A, B any](fa GA, f func(B, A) B, initial B) B { return array.Reduce(fa, f, initial) } func MonadReduceWithIndex[GA ~[]A, A, B any](fa GA, f func(int, B, A) B, initial B) B { return array.ReduceWithIndex(fa, f, initial) } func MonadReduceRight[GA ~[]A, A, B any](fa GA, f func(A, B) B, initial B) B { return array.ReduceRight(fa, f, initial) } func MonadReduceRightWithIndex[GA ~[]A, A, B any](fa GA, f func(int, A, B) B, initial B) B { return array.ReduceRightWithIndex(fa, f, initial) } // From constructs an array from a set of variadic arguments func From[GA ~[]A, A any](data ...A) GA { return data } // MakeBy returns a `Array` of length `n` with element `i` initialized with `f(i)`. func MakeBy[AS ~[]A, F ~func(int) A, A any](n int, f F) AS { // sanity check if n <= 0 { return Empty[AS]() } // run the generator function across the input as := make(AS, n) for i := n - 1; i >= 0; i-- { as[i] = f(i) } return as } func Replicate[AS ~[]A, A any](n int, a A) AS { return MakeBy[AS](n, F.Constant1[int](a)) } func Lookup[GA ~[]A, A any](idx int) func(GA) O.Option[A] { none := O.None[A]() if idx < 0 { return F.Constant1[GA](none) } return func(as GA) O.Option[A] { if idx < len(as) { return O.Some(as[idx]) } return none } } func Tail[GA ~[]A, A any](as GA) O.Option[GA] { if array.IsEmpty(as) { return O.None[GA]() } return O.Some(as[1:]) } func Head[GA ~[]A, A any](as GA) O.Option[A] { if array.IsEmpty(as) { return O.None[A]() } return O.Some(as[0]) } func First[GA ~[]A, A any](as GA) O.Option[A] { return Head(as) } func Last[GA ~[]A, A any](as GA) O.Option[A] { if array.IsEmpty(as) { return O.None[A]() } return O.Some(as[len(as)-1]) } func Append[GA ~[]A, A any](as GA, a A) GA { return array.Append(as, a) } func Empty[GA ~[]A, A any]() GA { return array.Empty[GA]() } func UpsertAt[GA ~[]A, A any](a A) func(GA) GA { return array.UpsertAt[GA](a) } func MonadMap[GA ~[]A, GB ~[]B, A, B any](as GA, f func(a A) B) GB { return array.MonadMap[GA, GB](as, f) } func Map[GA ~[]A, GB ~[]B, A, B any](f func(a A) B) func(GA) GB { return F.Bind2nd(MonadMap[GA, GB, A, B], f) } func MonadMapWithIndex[GA ~[]A, GB ~[]B, A, B any](as GA, f func(int, A) B) GB { return array.MonadMapWithIndex[GA, GB](as, f) } func MapWithIndex[GA ~[]A, GB ~[]B, A, B any](f func(int, A) B) func(GA) GB { return F.Bind2nd(MonadMapWithIndex[GA, GB, A, B], f) } func Size[GA ~[]A, A any](as GA) int { return len(as) } func filterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(A) O.Option[B]) GB { return array.Reduce(fa, func(bs GB, a A) GB { return O.MonadFold(f(a), F.Constant(bs), F.Bind1st(Append[GB, B], bs)) }, Empty[GB]()) } func filterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(int, A) O.Option[B]) GB { return array.ReduceWithIndex(fa, func(idx int, bs GB, a A) GB { return O.MonadFold(f(idx, a), F.Constant(bs), F.Bind1st(Append[GB, B], bs)) }, Empty[GB]()) } func MonadFilterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(A) O.Option[B]) GB { return filterMap[GA, GB](fa, f) } func MonadFilterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(int, A) O.Option[B]) GB { return filterMapWithIndex[GA, GB](fa, f) } func filterWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](fa AS, pred PRED) AS { result := make(AS, 0, len(fa)) for i, a := range fa { if pred(i, a) { result = append(result, a) } } return result } func FilterWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) AS { return F.Bind2nd(filterWithIndex[AS, PRED, A], pred) } func Filter[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) AS { return FilterWithIndex[AS](F.Ignore1of2[int](pred)) } func FilterChain[GA ~[]A, GB ~[]B, A, B any](f func(a A) O.Option[GB]) func(GA) GB { return F.Flow2( FilterMap[GA, []GB](f), Flatten[[]GB], ) } func Flatten[GAA ~[]GA, GA ~[]A, A any](mma GAA) GA { return MonadChain(mma, F.Identity[GA]) } func FilterMap[GA ~[]A, GB ~[]B, A, B any](f func(A) O.Option[B]) func(GA) GB { return F.Bind2nd(MonadFilterMap[GA, GB, A, B], f) } func FilterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](f func(int, A) O.Option[B]) func(GA) GB { return F.Bind2nd(MonadFilterMapWithIndex[GA, GB, A, B], f) } func MonadPartition[GA ~[]A, A any](as GA, pred func(A) bool) tuple.Tuple2[GA, GA] { left := Empty[GA]() right := Empty[GA]() array.Reduce(as, func(c bool, a A) bool { if pred(a) { right = append(right, a) } else { left = append(left, a) } return c }, true) // returns the partition return tuple.MakeTuple2(left, right) } func Partition[GA ~[]A, A any](pred func(A) bool) func(GA) tuple.Tuple2[GA, GA] { return F.Bind2nd(MonadPartition[GA, A], pred) } func MonadChain[AS ~[]A, BS ~[]B, A, B any](fa AS, f func(a A) BS) BS { return array.Reduce(fa, func(bs BS, a A) BS { return append(bs, f(a)...) }, Empty[BS]()) } func Chain[AS ~[]A, BS ~[]B, A, B any](f func(A) BS) func(AS) BS { return F.Bind2nd(MonadChain[AS, BS, A, B], f) } func MonadAp[BS ~[]B, ABS ~[]func(A) B, AS ~[]A, B, A any](fab ABS, fa AS) BS { return MonadChain(fab, F.Bind1st(MonadMap[AS, BS, A, B], fa)) } func Ap[BS ~[]B, ABS ~[]func(A) B, AS ~[]A, B, A any](fa AS) func(ABS) BS { return F.Bind2nd(MonadAp[BS, ABS, AS], fa) } func IsEmpty[AS ~[]A, A any](as AS) bool { return array.IsEmpty(as) } func IsNil[GA ~[]A, A any](as GA) bool { return array.IsNil(as) } func IsNonNil[GA ~[]A, A any](as GA) bool { return array.IsNonNil(as) } func Match[AS ~[]A, A, B any](onEmpty func() B, onNonEmpty func(AS) B) func(AS) B { return func(as AS) B { if IsEmpty(as) { return onEmpty() } return onNonEmpty(as) } } func MatchLeft[AS ~[]A, A, B any](onEmpty func() B, onNonEmpty func(A, AS) B) func(AS) B { return func(as AS) B { if IsEmpty(as) { return onEmpty() } return onNonEmpty(as[0], as[1:]) } } func Slice[AS ~[]A, A any](start int, end int) func(AS) AS { return func(a AS) AS { return a[start:end] } } func SliceRight[AS ~[]A, A any](start int) func(AS) AS { return func(a AS) AS { return a[start:] } } func Copy[AS ~[]A, A any](b AS) AS { buf := make(AS, len(b)) copy(buf, b) return buf } func Clone[AS ~[]A, A any](f func(A) A) func(as AS) AS { // implementation assumes that map does not optimize for the empty array return Map[AS, AS](f) } func FoldMap[AS ~[]A, A, B any](m M.Monoid[B]) func(func(A) B) func(AS) B { return func(f func(A) B) func(AS) B { return func(as AS) B { return array.Reduce(as, func(cur B, a A) B { return m.Concat(cur, f(a)) }, m.Empty()) } } } func FoldMapWithIndex[AS ~[]A, A, B any](m M.Monoid[B]) func(func(int, A) B) func(AS) B { return func(f func(int, A) B) func(AS) B { return func(as AS) B { return array.ReduceWithIndex(as, func(idx int, cur B, a A) B { return m.Concat(cur, f(idx, a)) }, m.Empty()) } } } func Fold[AS ~[]A, A any](m M.Monoid[A]) func(AS) A { return func(as AS) A { return array.Reduce(as, m.Concat, m.Empty()) } } func Push[GA ~[]A, A any](a A) func(GA) GA { return F.Bind2nd(array.Push[GA, A], a) } func MonadFlap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](fab GFAB, a A) GB { return FC.MonadFlap(MonadMap[GFAB, GB], fab, a) } func Flap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](a A) func(GFAB) GB { return F.Bind2nd(MonadFlap[FAB, GFAB, GB, A, B], a) }