From c6734ea01349e303f75302db2d3ffe1162e467fd Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 14 Aug 2024 17:56:24 -0700 Subject: [PATCH] fn: breaking - reverse argument order in slice funcs --- fn/list_test.go | 2 +- fn/slice.go | 42 ++++++++++++++----------------- fn/slice_test.go | 64 ++++++++++++++++++++++++------------------------ 3 files changed, 52 insertions(+), 56 deletions(-) diff --git a/fn/list_test.go b/fn/list_test.go index efe2c5a92..a2a1261a0 100644 --- a/fn/list_test.go +++ b/fn/list_test.go @@ -743,7 +743,7 @@ func TestFilterIdempotence(t *testing.T) { filtered := l.Filter(pred) - filteredAgain := Filter(pred, filtered) + filteredAgain := Filter(filtered, pred) return slices.Equal(filtered, filteredAgain) }, diff --git a/fn/slice.go b/fn/slice.go index 4dd4a2c58..afd8e0f7f 100644 --- a/fn/slice.go +++ b/fn/slice.go @@ -17,7 +17,7 @@ type Number interface { // All returns true when the supplied predicate evaluates to true for all of // the values in the slice. -func All[A any](pred func(A) bool, s []A) bool { +func All[A any](s []A, pred Pred[A]) bool { for _, val := range s { if !pred(val) { return false @@ -29,7 +29,7 @@ func All[A any](pred func(A) bool, s []A) bool { // Any returns true when the supplied predicate evaluates to true for any of // the values in the slice. -func Any[A any](pred func(A) bool, s []A) bool { +func Any[A any](s []A, pred Pred[A]) bool { for _, val := range s { if pred(val) { return true @@ -41,7 +41,7 @@ func Any[A any](pred func(A) bool, s []A) bool { // Map applies the function argument to all members of the slice and returns a // slice of those return values. -func Map[A, B any](f func(A) B, s []A) []B { +func Map[A, B any](s []A, f func(A) B) []B { res := make([]B, 0, len(s)) for _, val := range s { @@ -53,7 +53,7 @@ func Map[A, B any](f func(A) B, s []A) []B { // Filter creates a new slice of values where all the members of the returned // slice pass the predicate that is supplied in the argument. -func Filter[A any](pred Pred[A], s []A) []A { +func Filter[A any](s []A, pred Pred[A]) []A { res := make([]A, 0) for _, val := range s { @@ -96,7 +96,7 @@ func TrimNones[A any](as []Option[A]) []A { // Foldl iterates through all members of the slice left to right and reduces // them pairwise with an accumulator value that is seeded with the seed value in // the argument. -func Foldl[A, B any](f func(B, A) B, seed B, s []A) B { +func Foldl[A, B any](seed B, s []A, f func(B, A) B) B { acc := seed for _, val := range s { @@ -108,7 +108,7 @@ func Foldl[A, B any](f func(B, A) B, seed B, s []A) B { // Foldr, is exactly like Foldl except that it iterates over the slice from // right to left. -func Foldr[A, B any](f func(A, B) B, seed B, s []A) B { +func Foldr[A, B any](seed B, s []A, f func(A, B) B) B { acc := seed for i := range s { @@ -120,7 +120,7 @@ func Foldr[A, B any](f func(A, B) B, seed B, s []A) B { // Find returns the first value that passes the supplied predicate, or None if // the value wasn't found. -func Find[A any](pred Pred[A], s []A) Option[A] { +func Find[A any](s []A, pred Pred[A]) Option[A] { for _, val := range s { if pred(val) { return Some(val) @@ -132,7 +132,7 @@ func Find[A any](pred Pred[A], s []A) Option[A] { // FindIdx returns the first value that passes the supplied predicate along with // its index in the slice. If no satisfactory value is found, None is returned. -func FindIdx[A any](pred Pred[A], s []A) Option[T2[int, A]] { +func FindIdx[A any](s []A, pred Pred[A]) Option[T2[int, A]] { for i, val := range s { if pred(val) { return Some(NewT2[int, A](i, val)) @@ -144,16 +144,14 @@ func FindIdx[A any](pred Pred[A], s []A) Option[T2[int, A]] { // Elem returns true if the element in the argument is found in the slice func Elem[A comparable](a A, s []A) bool { - return Any(Eq(a), s) + return Any(s, Eq(a)) } // Flatten takes a slice of slices and returns a concatenation of those slices. func Flatten[A any](s [][]A) []A { - sz := Foldr( - func(l []A, acc uint64) uint64 { - return uint64(len(l)) + acc - }, 0, s, - ) + sz := Foldr(0, s, func(l []A, acc uint64) uint64 { + return uint64(len(l)) + acc + }) res := make([]A, 0, sz) @@ -178,7 +176,7 @@ func Replicate[A any](n uint, val A) []A { // Span, applied to a predicate and a slice, returns two slices where the first // element is the longest prefix (possibly empty) of slice elements that // satisfy the predicate and second element is the remainder of the slice. -func Span[A any](pred func(A) bool, s []A) ([]A, []A) { +func Span[A any](s []A, pred Pred[A]) ([]A, []A) { for i := range s { if !pred(s[i]) { fst := make([]A, i) @@ -211,7 +209,7 @@ func SplitAt[A any](n uint, s []A) ([]A, []A) { // ZipWith combines slice elements with the same index using the function // argument, returning a slice of the results. -func ZipWith[A, B, C any](f func(A, B) C, a []A, b []B) []C { +func ZipWith[A, B, C any](a []A, b []B, f func(A, B) C) []C { var l uint if la, lb := len(a), len(b); la < lb { @@ -246,9 +244,9 @@ func SliceToMap[A any, K comparable, V any](s []A, keyFunc func(A) K, // Sum calculates the sum of a slice of numbers, `items`. func Sum[B Number](items []B) B { - return Foldl(func(a, b B) B { + return Foldl(0, items, func(a, b B) B { return a + b - }, 0, items) + }) } // HasDuplicates checks if the given slice contains any duplicate elements. @@ -261,9 +259,7 @@ func HasDuplicates[A comparable](items []A) bool { // ForEachConc maps the argument function over the slice, spawning a new // goroutine for each element in the slice and then awaits all results before // returning them. -func ForEachConc[A, B any](f func(A) B, - as []A) []B { - +func ForEachConc[A, B any](as []A, f func(A) B) []B { var wait sync.WaitGroup ctx := context.Background() @@ -360,7 +356,7 @@ func CollectOptions[A any](options []Option[A]) Option[[]A] { // Now that we're sure we have no Nones, we can just do an unchecked // index into the some value of the option. - return Some(Map(func(o Option[A]) A { return o.some }, options)) + return Some(Map(options, func(o Option[A]) A { return o.some })) } // CollectResults collects a list of Results into a single Result of the list of @@ -377,7 +373,7 @@ func CollectResults[A any](results []Result[A]) Result[[]A] { // Now that we're sure we have no errors, we can just do an unchecked // index into the left side of the result. - return Ok(Map(func(r Result[A]) A { return r.left }, results)) + return Ok(Map(results, func(r Result[A]) A { return r.left })) } // TraverseOption traverses a slice of A values, applying the provided diff --git a/fn/slice_test.go b/fn/slice_test.go index 18f7602ad..961196973 100644 --- a/fn/slice_test.go +++ b/fn/slice_test.go @@ -16,30 +16,30 @@ func odd(a int) bool { return a%2 != 0 } func TestAll(t *testing.T) { x := []int{0, 2, 4, 6, 8} - require.True(t, All(even, x)) - require.False(t, All(odd, x)) + require.True(t, All(x, even)) + require.False(t, All(x, odd)) y := []int{1, 3, 5, 7, 9} - require.False(t, All(even, y)) - require.True(t, All(odd, y)) + require.False(t, All(y, even)) + require.True(t, All(y, odd)) z := []int{0, 2, 4, 6, 9} - require.False(t, All(even, z)) - require.False(t, All(odd, z)) + require.False(t, All(z, even)) + require.False(t, All(z, odd)) } func TestAny(t *testing.T) { x := []int{1, 3, 5, 7, 9} - require.False(t, Any(even, x)) - require.True(t, Any(odd, x)) + require.False(t, Any(x, even)) + require.True(t, Any(x, odd)) y := []int{0, 3, 5, 7, 9} - require.True(t, Any(even, y)) - require.True(t, Any(odd, y)) + require.True(t, Any(y, even)) + require.True(t, Any(y, odd)) z := []int{0, 2, 4, 6, 8} - require.True(t, Any(even, z)) - require.False(t, Any(odd, z)) + require.True(t, Any(z, even)) + require.False(t, Any(z, odd)) } func TestMap(t *testing.T) { @@ -47,7 +47,7 @@ func TestMap(t *testing.T) { x := []int{0, 2, 4, 6, 8} - y := Map(inc, x) + y := Map(x, inc) z := []int{1, 3, 5, 7, 9} @@ -57,11 +57,11 @@ func TestMap(t *testing.T) { func TestFilter(t *testing.T) { x := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} - y := Filter(even, x) + y := Filter(x, even) - require.True(t, All(even, y)) + require.True(t, All(y, even)) - z := Filter(odd, y) + z := Filter(y, odd) require.Zero(t, len(z)) } @@ -72,7 +72,7 @@ func TestFoldl(t *testing.T) { x := []int{0, 1, 2, 3, 4} - r := Foldl(stupid, seed, x) + r := Foldl(seed, x, stupid) require.True(t, slices.Equal(x, r)) } @@ -83,7 +83,7 @@ func TestFoldr(t *testing.T) { x := []int{0, 1, 2, 3, 4} - z := Foldr(stupid, seed, x) + z := Foldr(seed, x, stupid) slices.Reverse[[]int](x) @@ -96,9 +96,9 @@ func TestFind(t *testing.T) { div3 := func(a int) bool { return a%3 == 0 } div8 := func(a int) bool { return a%8 == 0 } - require.Equal(t, Find(div3, x), Some(12)) + require.Equal(t, Find(x, div3), Some(12)) - require.Equal(t, Find(div8, x), None[int]()) + require.Equal(t, Find(x, div8), None[int]()) } func TestFlatten(t *testing.T) { @@ -117,7 +117,7 @@ func TestSpan(t *testing.T) { x := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} lt5 := func(a int) bool { return a < 5 } - low, high := Span(lt5, x) + low, high := Span(x, lt5) require.True(t, slices.Equal(low, []int{0, 1, 2, 3, 4})) require.True(t, slices.Equal(high, []int{5, 6, 7, 8, 9})) @@ -135,7 +135,7 @@ func TestZipWith(t *testing.T) { eq := func(a, b int) bool { return a == b } x := []int{0, 1, 2, 3, 4} y := Replicate(5, 1) - z := ZipWith(eq, x, y) + z := ZipWith(x, y, eq) require.True(t, slices.Equal( z, []bool{false, true, false, false, false}, )) @@ -290,8 +290,8 @@ func TestHasDuplicates(t *testing.T) { func TestPropForEachConcMapIsomorphism(t *testing.T) { f := func(incSize int, s []int) bool { inc := func(i int) int { return i + incSize } - mapped := Map(inc, s) - conc := ForEachConc(inc, s) + mapped := Map(s, inc) + conc := ForEachConc(s, inc) return slices.Equal(mapped, conc) } @@ -319,7 +319,7 @@ func TestPropForEachConcOutperformsMapWhenExpensive(t *testing.T) { c := make(chan bool, 1) go func() { - Map(inc, s) + Map(s, inc) select { case c <- false: default: @@ -327,7 +327,7 @@ func TestPropForEachConcOutperformsMapWhenExpensive(t *testing.T) { }() go func() { - ForEachConc(inc, s) + ForEachConc(s, inc) select { case c <- true: default: @@ -352,14 +352,14 @@ func TestPropFindIdxFindIdentity(t *testing.T) { return i%div == mod } - foundIdx := FindIdx(pred, s) + foundIdx := FindIdx(s, pred) // onlyVal :: Option[T2[A, B]] -> Option[B] onlyVal := MapOption(func(t2 T2[int, uint8]) uint8 { return t2.Second() }) - valuesEqual := Find(pred, s) == onlyVal(foundIdx) + valuesEqual := Find(s, pred) == onlyVal(foundIdx) idxGetsVal := ElimOption( foundIdx, @@ -584,7 +584,7 @@ func TestPropCollectResultsSingleErrEjection(t *testing.T) { return Ok(i) } - return CollectResults(Map(f, s)).IsErr() + return CollectResults(Map(s, f)).IsErr() } require.NoError(t, quick.Check(f, nil)) @@ -594,7 +594,7 @@ func TestPropCollectResultsSingleErrEjection(t *testing.T) { // results then we end up with unwrapping all of the Results in the slice. func TestPropCollectResultsNoErrUnwrap(t *testing.T) { f := func(s []int) bool { - res := CollectResults(Map(Ok[int], s)) + res := CollectResults(Map(s, Ok[int])) return !res.isRight && slices.Equal(res.left, s) } @@ -660,7 +660,7 @@ func TestPropCollectOptionsSingleNoneEjection(t *testing.T) { return Some(i) } - return CollectOptions(Map(f, s)).IsNone() + return CollectOptions(Map(s, f)).IsNone() } require.NoError(t, quick.Check(f, nil)) @@ -670,7 +670,7 @@ func TestPropCollectOptionsSingleNoneEjection(t *testing.T) { // options then we end up with unwrapping all of the Options in the slice. func TestPropCollectOptionsNoNoneUnwrap(t *testing.T) { f := func(s []int) bool { - res := CollectOptions(Map(Some[int], s)) + res := CollectOptions(Map(s, Some[int])) return res.isSome && slices.Equal(res.some, s) }