2023-07-23 22:05:54 +02:00
|
|
|
// 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.
|
|
|
|
|
2023-07-07 22:31:06 +02:00
|
|
|
package generic
|
|
|
|
|
|
|
|
import (
|
2023-07-18 15:57:54 +02:00
|
|
|
F "github.com/IBM/fp-go/function"
|
|
|
|
"github.com/IBM/fp-go/internal/array"
|
2023-09-26 22:32:53 +02:00
|
|
|
FC "github.com/IBM/fp-go/internal/functor"
|
2023-08-10 18:08:11 +02:00
|
|
|
M "github.com/IBM/fp-go/monoid"
|
2023-07-18 15:57:54 +02:00
|
|
|
O "github.com/IBM/fp-go/option"
|
|
|
|
"github.com/IBM/fp-go/tuple"
|
2023-07-07 22:31:06 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// Of constructs a single element array
|
|
|
|
func Of[GA ~[]A, A any](value A) GA {
|
|
|
|
return GA{value}
|
|
|
|
}
|
|
|
|
|
2023-11-11 16:50:18 +01:00
|
|
|
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 {
|
2023-08-24 22:49:03 +02:00
|
|
|
return array.Reduce(fa, f, initial)
|
|
|
|
}
|
|
|
|
|
2023-11-11 16:50:18 +01:00
|
|
|
func MonadReduceWithIndex[GA ~[]A, A, B any](fa GA, f func(int, B, A) B, initial B) B {
|
2023-08-24 22:49:03 +02:00
|
|
|
return array.ReduceWithIndex(fa, f, initial)
|
|
|
|
}
|
|
|
|
|
2023-11-11 16:50:18 +01:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2023-07-07 22:31:06 +02:00
|
|
|
// From constructs an array from a set of variadic arguments
|
|
|
|
func From[GA ~[]A, A any](data ...A) GA {
|
|
|
|
return data
|
|
|
|
}
|
|
|
|
|
2023-07-20 16:17:23 +02:00
|
|
|
// 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))
|
|
|
|
}
|
|
|
|
|
2023-07-07 22:31:06 +02:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2023-08-22 22:34:05 +02:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2023-11-25 16:56:39 +01:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2023-07-07 22:31:06 +02:00
|
|
|
func Size[GA ~[]A, A any](as GA) int {
|
|
|
|
return len(as)
|
|
|
|
}
|
|
|
|
|
2023-11-11 16:50:18 +01:00
|
|
|
func filterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(A) O.Option[B]) GB {
|
2023-07-07 22:31:06 +02:00
|
|
|
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]())
|
|
|
|
}
|
|
|
|
|
2023-11-11 16:50:18 +01:00
|
|
|
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 {
|
2023-07-07 22:31:06 +02:00
|
|
|
return filterMap[GA, GB](fa, f)
|
|
|
|
}
|
|
|
|
|
2023-11-11 16:50:18 +01:00
|
|
|
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))
|
|
|
|
}
|
|
|
|
|
2023-08-10 11:46:30 +02:00
|
|
|
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])
|
|
|
|
}
|
|
|
|
|
2023-11-11 16:50:18 +01:00
|
|
|
func FilterMap[GA ~[]A, GB ~[]B, A, B any](f func(A) O.Option[B]) func(GA) GB {
|
2023-07-07 22:31:06 +02:00
|
|
|
return F.Bind2nd(MonadFilterMap[GA, GB, A, B], f)
|
|
|
|
}
|
|
|
|
|
2023-11-11 16:50:18 +01:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2023-07-07 22:31:06 +02:00
|
|
|
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)
|
|
|
|
}
|
2023-07-20 16:17:23 +02:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
2023-07-24 16:43:07 +02:00
|
|
|
|
|
|
|
func IsEmpty[AS ~[]A, A any](as AS) bool {
|
|
|
|
return array.IsEmpty(as)
|
|
|
|
}
|
|
|
|
|
2023-09-10 21:49:44 +02:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2023-07-24 16:43:07 +02:00
|
|
|
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:])
|
|
|
|
}
|
|
|
|
}
|
2023-07-28 22:50:52 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
2023-08-10 18:08:11 +02:00
|
|
|
|
|
|
|
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())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-25 16:56:39 +01:00
|
|
|
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())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-10 18:08:11 +02:00
|
|
|
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())
|
|
|
|
}
|
|
|
|
}
|
2023-08-24 22:49:03 +02:00
|
|
|
|
|
|
|
func Push[GA ~[]A, A any](a A) func(GA) GA {
|
|
|
|
return F.Bind2nd(array.Push[GA, A], a)
|
|
|
|
}
|
2023-09-26 22:32:53 +02:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|