fn: breaking - reverse argument order in slice funcs

This commit is contained in:
Keagan McClelland
2024-08-14 17:56:24 -07:00
parent a026d64c1b
commit c6734ea013
3 changed files with 52 additions and 56 deletions

View File

@@ -743,7 +743,7 @@ func TestFilterIdempotence(t *testing.T) {
filtered := l.Filter(pred) filtered := l.Filter(pred)
filteredAgain := Filter(pred, filtered) filteredAgain := Filter(filtered, pred)
return slices.Equal(filtered, filteredAgain) return slices.Equal(filtered, filteredAgain)
}, },

View File

@@ -17,7 +17,7 @@ type Number interface {
// All returns true when the supplied predicate evaluates to true for all of // All returns true when the supplied predicate evaluates to true for all of
// the values in the slice. // 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 { for _, val := range s {
if !pred(val) { if !pred(val) {
return false 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 // Any returns true when the supplied predicate evaluates to true for any of
// the values in the slice. // 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 { for _, val := range s {
if pred(val) { if pred(val) {
return true 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 // Map applies the function argument to all members of the slice and returns a
// slice of those return values. // 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)) res := make([]B, 0, len(s))
for _, val := range 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 // Filter creates a new slice of values where all the members of the returned
// slice pass the predicate that is supplied in the argument. // 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) res := make([]A, 0)
for _, val := range s { 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 // 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 // them pairwise with an accumulator value that is seeded with the seed value in
// the argument. // 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 acc := seed
for _, val := range s { 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 // Foldr, is exactly like Foldl except that it iterates over the slice from
// right to left. // 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 acc := seed
for i := range s { 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 // Find returns the first value that passes the supplied predicate, or None if
// the value wasn't found. // 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 { for _, val := range s {
if pred(val) { if pred(val) {
return Some(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 // 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. // 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 { for i, val := range s {
if pred(val) { if pred(val) {
return Some(NewT2[int, A](i, 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 // Elem returns true if the element in the argument is found in the slice
func Elem[A comparable](a A, s []A) bool { 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. // Flatten takes a slice of slices and returns a concatenation of those slices.
func Flatten[A any](s [][]A) []A { func Flatten[A any](s [][]A) []A {
sz := Foldr( sz := Foldr(0, s, func(l []A, acc uint64) uint64 {
func(l []A, acc uint64) uint64 { return uint64(len(l)) + acc
return uint64(len(l)) + acc })
}, 0, s,
)
res := make([]A, 0, sz) 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 // 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 // element is the longest prefix (possibly empty) of slice elements that
// satisfy the predicate and second element is the remainder of the slice. // 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 { for i := range s {
if !pred(s[i]) { if !pred(s[i]) {
fst := make([]A, 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 // ZipWith combines slice elements with the same index using the function
// argument, returning a slice of the results. // 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 var l uint
if la, lb := len(a), len(b); la < lb { 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`. // Sum calculates the sum of a slice of numbers, `items`.
func Sum[B Number](items []B) B { 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 return a + b
}, 0, items) })
} }
// HasDuplicates checks if the given slice contains any duplicate elements. // 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 // ForEachConc maps the argument function over the slice, spawning a new
// goroutine for each element in the slice and then awaits all results before // goroutine for each element in the slice and then awaits all results before
// returning them. // returning them.
func ForEachConc[A, B any](f func(A) B, func ForEachConc[A, B any](as []A, f func(A) B) []B {
as []A) []B {
var wait sync.WaitGroup var wait sync.WaitGroup
ctx := context.Background() 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 // Now that we're sure we have no Nones, we can just do an unchecked
// index into the some value of the option. // 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 // 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 // Now that we're sure we have no errors, we can just do an unchecked
// index into the left side of the result. // 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 // TraverseOption traverses a slice of A values, applying the provided

View File

@@ -16,30 +16,30 @@ func odd(a int) bool { return a%2 != 0 }
func TestAll(t *testing.T) { func TestAll(t *testing.T) {
x := []int{0, 2, 4, 6, 8} x := []int{0, 2, 4, 6, 8}
require.True(t, All(even, x)) require.True(t, All(x, even))
require.False(t, All(odd, x)) require.False(t, All(x, odd))
y := []int{1, 3, 5, 7, 9} y := []int{1, 3, 5, 7, 9}
require.False(t, All(even, y)) require.False(t, All(y, even))
require.True(t, All(odd, y)) require.True(t, All(y, odd))
z := []int{0, 2, 4, 6, 9} z := []int{0, 2, 4, 6, 9}
require.False(t, All(even, z)) require.False(t, All(z, even))
require.False(t, All(odd, z)) require.False(t, All(z, odd))
} }
func TestAny(t *testing.T) { func TestAny(t *testing.T) {
x := []int{1, 3, 5, 7, 9} x := []int{1, 3, 5, 7, 9}
require.False(t, Any(even, x)) require.False(t, Any(x, even))
require.True(t, Any(odd, x)) require.True(t, Any(x, odd))
y := []int{0, 3, 5, 7, 9} y := []int{0, 3, 5, 7, 9}
require.True(t, Any(even, y)) require.True(t, Any(y, even))
require.True(t, Any(odd, y)) require.True(t, Any(y, odd))
z := []int{0, 2, 4, 6, 8} z := []int{0, 2, 4, 6, 8}
require.True(t, Any(even, z)) require.True(t, Any(z, even))
require.False(t, Any(odd, z)) require.False(t, Any(z, odd))
} }
func TestMap(t *testing.T) { func TestMap(t *testing.T) {
@@ -47,7 +47,7 @@ func TestMap(t *testing.T) {
x := []int{0, 2, 4, 6, 8} x := []int{0, 2, 4, 6, 8}
y := Map(inc, x) y := Map(x, inc)
z := []int{1, 3, 5, 7, 9} z := []int{1, 3, 5, 7, 9}
@@ -57,11 +57,11 @@ func TestMap(t *testing.T) {
func TestFilter(t *testing.T) { func TestFilter(t *testing.T) {
x := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 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)) require.Zero(t, len(z))
} }
@@ -72,7 +72,7 @@ func TestFoldl(t *testing.T) {
x := []int{0, 1, 2, 3, 4} x := []int{0, 1, 2, 3, 4}
r := Foldl(stupid, seed, x) r := Foldl(seed, x, stupid)
require.True(t, slices.Equal(x, r)) require.True(t, slices.Equal(x, r))
} }
@@ -83,7 +83,7 @@ func TestFoldr(t *testing.T) {
x := []int{0, 1, 2, 3, 4} x := []int{0, 1, 2, 3, 4}
z := Foldr(stupid, seed, x) z := Foldr(seed, x, stupid)
slices.Reverse[[]int](x) slices.Reverse[[]int](x)
@@ -96,9 +96,9 @@ func TestFind(t *testing.T) {
div3 := func(a int) bool { return a%3 == 0 } div3 := func(a int) bool { return a%3 == 0 }
div8 := func(a int) bool { return a%8 == 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) { 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} x := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
lt5 := func(a int) bool { return a < 5 } 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(low, []int{0, 1, 2, 3, 4}))
require.True(t, slices.Equal(high, []int{5, 6, 7, 8, 9})) 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 } eq := func(a, b int) bool { return a == b }
x := []int{0, 1, 2, 3, 4} x := []int{0, 1, 2, 3, 4}
y := Replicate(5, 1) y := Replicate(5, 1)
z := ZipWith(eq, x, y) z := ZipWith(x, y, eq)
require.True(t, slices.Equal( require.True(t, slices.Equal(
z, []bool{false, true, false, false, false}, z, []bool{false, true, false, false, false},
)) ))
@@ -290,8 +290,8 @@ func TestHasDuplicates(t *testing.T) {
func TestPropForEachConcMapIsomorphism(t *testing.T) { func TestPropForEachConcMapIsomorphism(t *testing.T) {
f := func(incSize int, s []int) bool { f := func(incSize int, s []int) bool {
inc := func(i int) int { return i + incSize } inc := func(i int) int { return i + incSize }
mapped := Map(inc, s) mapped := Map(s, inc)
conc := ForEachConc(inc, s) conc := ForEachConc(s, inc)
return slices.Equal(mapped, conc) return slices.Equal(mapped, conc)
} }
@@ -319,7 +319,7 @@ func TestPropForEachConcOutperformsMapWhenExpensive(t *testing.T) {
c := make(chan bool, 1) c := make(chan bool, 1)
go func() { go func() {
Map(inc, s) Map(s, inc)
select { select {
case c <- false: case c <- false:
default: default:
@@ -327,7 +327,7 @@ func TestPropForEachConcOutperformsMapWhenExpensive(t *testing.T) {
}() }()
go func() { go func() {
ForEachConc(inc, s) ForEachConc(s, inc)
select { select {
case c <- true: case c <- true:
default: default:
@@ -352,14 +352,14 @@ func TestPropFindIdxFindIdentity(t *testing.T) {
return i%div == mod return i%div == mod
} }
foundIdx := FindIdx(pred, s) foundIdx := FindIdx(s, pred)
// onlyVal :: Option[T2[A, B]] -> Option[B] // onlyVal :: Option[T2[A, B]] -> Option[B]
onlyVal := MapOption(func(t2 T2[int, uint8]) uint8 { onlyVal := MapOption(func(t2 T2[int, uint8]) uint8 {
return t2.Second() return t2.Second()
}) })
valuesEqual := Find(pred, s) == onlyVal(foundIdx) valuesEqual := Find(s, pred) == onlyVal(foundIdx)
idxGetsVal := ElimOption( idxGetsVal := ElimOption(
foundIdx, foundIdx,
@@ -584,7 +584,7 @@ func TestPropCollectResultsSingleErrEjection(t *testing.T) {
return Ok(i) return Ok(i)
} }
return CollectResults(Map(f, s)).IsErr() return CollectResults(Map(s, f)).IsErr()
} }
require.NoError(t, quick.Check(f, nil)) 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. // results then we end up with unwrapping all of the Results in the slice.
func TestPropCollectResultsNoErrUnwrap(t *testing.T) { func TestPropCollectResultsNoErrUnwrap(t *testing.T) {
f := func(s []int) bool { 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) return !res.isRight && slices.Equal(res.left, s)
} }
@@ -660,7 +660,7 @@ func TestPropCollectOptionsSingleNoneEjection(t *testing.T) {
return Some(i) return Some(i)
} }
return CollectOptions(Map(f, s)).IsNone() return CollectOptions(Map(s, f)).IsNone()
} }
require.NoError(t, quick.Check(f, nil)) 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. // options then we end up with unwrapping all of the Options in the slice.
func TestPropCollectOptionsNoNoneUnwrap(t *testing.T) { func TestPropCollectOptionsNoNoneUnwrap(t *testing.T) {
f := func(s []int) bool { 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) return res.isSome && slices.Equal(res.some, s)
} }