diff --git a/v2/README.md b/v2/README.md index e333f77..f24285d 100644 --- a/v2/README.md +++ b/v2/README.md @@ -69,7 +69,7 @@ func main() { none := option.None[int]() // Map over values - doubled := option.Map(func(x int) int { return x * 2 })(some) + doubled := option.Map(N.Mul(2))(some) fmt.Println(option.GetOrElse(0)(doubled)) // Output: 84 // Chain operations @@ -187,7 +187,7 @@ Monadic operations for `Pair` now operate on the **second argument** to align wi ```go // Operations on first element pair := MakePair(1, "hello") -result := Map(func(x int) int { return x * 2 })(pair) // Pair(2, "hello") +result := Map(N.Mul(2))(pair) // Pair(2, "hello") ``` **V2:** @@ -204,7 +204,7 @@ The `Compose` function for endomorphisms now follows **mathematical function com **V1:** ```go // Compose executed left-to-right -double := func(x int) int { return x * 2 } +double := N.Mul(2) increment := func(x int) int { return x + 1 } composed := Compose(double, increment) result := composed(5) // (5 * 2) + 1 = 11 @@ -213,7 +213,7 @@ result := composed(5) // (5 * 2) + 1 = 11 **V2:** ```go // Compose executes RIGHT-TO-LEFT (mathematical composition) -double := func(x int) int { return x * 2 } +double := N.Mul(2) increment := func(x int) int { return x + 1 } composed := Compose(double, increment) result := composed(5) // (5 + 1) * 2 = 12 @@ -368,7 +368,7 @@ If you're using `Pair`, update operations to work on the second element: ```go pair := MakePair(42, "data") // Map operates on first element -result := Map(func(x int) int { return x * 2 })(pair) +result := Map(N.Mul(2))(pair) ``` **After (V2):** diff --git a/v2/array/array.go b/v2/array/array.go index c8b55bd..cacd63c 100644 --- a/v2/array/array.go +++ b/v2/array/array.go @@ -76,7 +76,7 @@ func MapWithIndex[A, B any](f func(int, A) B) Operator[A, B] { // // Example: // -// double := array.Map(func(x int) int { return x * 2 }) +// double := array.Map(N.Mul(2)) // result := double([]int{1, 2, 3}) // [2, 4, 6] // //go:inline diff --git a/v2/array/doc.go b/v2/array/doc.go index dea4cfd..5182d68 100644 --- a/v2/array/doc.go +++ b/v2/array/doc.go @@ -36,7 +36,7 @@ // generated := array.MakeBy(5, func(i int) int { return i * 2 }) // // // Transforming arrays -// doubled := array.Map(func(x int) int { return x * 2 })(arr) +// doubled := array.Map(N.Mul(2))(arr) // filtered := array.Filter(func(x int) bool { return x > 2 })(arr) // // // Combining arrays @@ -50,7 +50,7 @@ // numbers := []int{1, 2, 3, 4, 5} // // // Map transforms each element -// doubled := array.Map(func(x int) int { return x * 2 })(numbers) +// doubled := array.Map(N.Mul(2))(numbers) // // Result: [2, 4, 6, 8, 10] // // // Filter keeps elements matching a predicate diff --git a/v2/array/slice_test.go b/v2/array/slice_test.go index 442f3dd..9c11fbe 100644 --- a/v2/array/slice_test.go +++ b/v2/array/slice_test.go @@ -18,6 +18,7 @@ package array import ( "testing" + N "github.com/IBM/fp-go/v2/number" "github.com/stretchr/testify/assert" ) @@ -243,7 +244,7 @@ func TestSliceComposition(t *testing.T) { t.Run("slice then map", func(t *testing.T) { sliced := Slice[int](2, 5)(data) - mapped := Map(func(x int) int { return x * 2 })(sliced) + mapped := Map(N.Mul(2))(sliced) assert.Equal(t, []int{4, 6, 8}, mapped) }) diff --git a/v2/bytes/bytes_test.go b/v2/bytes/bytes_test.go index f64d342..a7725c4 100644 --- a/v2/bytes/bytes_test.go +++ b/v2/bytes/bytes_test.go @@ -382,7 +382,7 @@ func BenchmarkToString(b *testing.B) { data := []byte("Hello, World!") b.Run("small", func(b *testing.B) { - for i := 0; i < b.N; i++ { + for b.Loop() { _ = ToString(data) } }) @@ -393,7 +393,7 @@ func BenchmarkToString(b *testing.B) { large[i] = byte(i % 256) } b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = ToString(large) } }) @@ -402,7 +402,7 @@ func BenchmarkToString(b *testing.B) { func BenchmarkSize(b *testing.B) { data := []byte("Hello, World!") - for i := 0; i < b.N; i++ { + for b.Loop() { _ = Size(data) } } @@ -412,7 +412,7 @@ func BenchmarkMonoidConcat(b *testing.B) { c := []byte(" World") b.Run("small slices", func(b *testing.B) { - for i := 0; i < b.N; i++ { + for b.Loop() { _ = Monoid.Concat(a, c) } }) @@ -421,7 +421,7 @@ func BenchmarkMonoidConcat(b *testing.B) { large1 := make([]byte, 10000) large2 := make([]byte, 10000) b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = Monoid.Concat(large1, large2) } }) @@ -436,7 +436,7 @@ func BenchmarkConcatAll(b *testing.B) { } b.Run("few slices", func(b *testing.B) { - for i := 0; i < b.N; i++ { + for b.Loop() { _ = ConcatAll(slices...) } }) @@ -447,7 +447,7 @@ func BenchmarkConcatAll(b *testing.B) { many[i] = []byte{byte(i)} } b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = ConcatAll(many...) } }) @@ -458,13 +458,13 @@ func BenchmarkOrdCompare(b *testing.B) { c := []byte("abd") b.Run("equal", func(b *testing.B) { - for i := 0; i < b.N; i++ { + for b.Loop() { _ = Ord.Compare(a, a) } }) b.Run("different", func(b *testing.B) { - for i := 0; i < b.N; i++ { + for b.Loop() { _ = Ord.Compare(a, c) } }) @@ -474,7 +474,7 @@ func BenchmarkOrdCompare(b *testing.B) { large2 := make([]byte, 10000) large2[9999] = 1 b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = Ord.Compare(large1, large2) } }) diff --git a/v2/context/readerioresult/reader_bench_test.go b/v2/context/readerioresult/reader_bench_test.go index 40e5a9d..6459e3e 100644 --- a/v2/context/readerioresult/reader_bench_test.go +++ b/v2/context/readerioresult/reader_bench_test.go @@ -24,6 +24,7 @@ import ( E "github.com/IBM/fp-go/v2/either" F "github.com/IBM/fp-go/v2/function" IOE "github.com/IBM/fp-go/v2/ioeither" + N "github.com/IBM/fp-go/v2/number" ) var ( @@ -37,21 +38,21 @@ var ( // Benchmark core constructors func BenchmarkLeft(b *testing.B) { b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = Left[int](benchErr) } } func BenchmarkRight(b *testing.B) { b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = Right(42) } } func BenchmarkOf(b *testing.B) { b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = Of(42) } } @@ -60,7 +61,7 @@ func BenchmarkFromEither_Right(b *testing.B) { either := E.Right[error](42) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = FromEither(either) } } @@ -69,7 +70,7 @@ func BenchmarkFromEither_Left(b *testing.B) { either := E.Left[int](benchErr) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = FromEither(either) } } @@ -77,7 +78,7 @@ func BenchmarkFromEither_Left(b *testing.B) { func BenchmarkFromIO(b *testing.B) { io := func() int { return 42 } b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = FromIO(io) } } @@ -85,7 +86,7 @@ func BenchmarkFromIO(b *testing.B) { func BenchmarkFromIOEither_Right(b *testing.B) { ioe := IOE.Of[error](42) b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = FromIOEither(ioe) } } @@ -93,7 +94,7 @@ func BenchmarkFromIOEither_Right(b *testing.B) { func BenchmarkFromIOEither_Left(b *testing.B) { ioe := IOE.Left[int](benchErr) b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = FromIOEither(ioe) } } @@ -103,7 +104,7 @@ func BenchmarkExecute_Right(b *testing.B) { rioe := Right(42) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = rioe(benchCtx)() } } @@ -112,7 +113,7 @@ func BenchmarkExecute_Left(b *testing.B) { rioe := Left[int](benchErr) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = rioe(benchCtx)() } } @@ -123,7 +124,7 @@ func BenchmarkExecute_WithContext(b *testing.B) { defer cancel() b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = rioe(ctx)() } } @@ -131,40 +132,40 @@ func BenchmarkExecute_WithContext(b *testing.B) { // Benchmark functor operations func BenchmarkMonadMap_Right(b *testing.B) { rioe := Right(42) - mapper := func(a int) int { return a * 2 } + mapper := N.Mul(2) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = MonadMap(rioe, mapper) } } func BenchmarkMonadMap_Left(b *testing.B) { rioe := Left[int](benchErr) - mapper := func(a int) int { return a * 2 } + mapper := N.Mul(2) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = MonadMap(rioe, mapper) } } func BenchmarkMap_Right(b *testing.B) { rioe := Right(42) - mapper := Map(func(a int) int { return a * 2 }) + mapper := Map(N.Mul(2)) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = mapper(rioe) } } func BenchmarkMap_Left(b *testing.B) { rioe := Left[int](benchErr) - mapper := Map(func(a int) int { return a * 2 }) + mapper := Map(N.Mul(2)) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = mapper(rioe) } } @@ -174,7 +175,7 @@ func BenchmarkMapTo_Right(b *testing.B) { mapper := MapTo[int](99) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = mapper(rioe) } } @@ -185,7 +186,7 @@ func BenchmarkMonadChain_Right(b *testing.B) { chainer := func(a int) ReaderIOResult[int] { return Right(a * 2) } b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = MonadChain(rioe, chainer) } } @@ -195,7 +196,7 @@ func BenchmarkMonadChain_Left(b *testing.B) { chainer := func(a int) ReaderIOResult[int] { return Right(a * 2) } b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = MonadChain(rioe, chainer) } } @@ -205,7 +206,7 @@ func BenchmarkChain_Right(b *testing.B) { chainer := Chain(func(a int) ReaderIOResult[int] { return Right(a * 2) }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = chainer(rioe) } } @@ -215,7 +216,7 @@ func BenchmarkChain_Left(b *testing.B) { chainer := Chain(func(a int) ReaderIOResult[int] { return Right(a * 2) }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = chainer(rioe) } } @@ -225,7 +226,7 @@ func BenchmarkChainFirst_Right(b *testing.B) { chainer := ChainFirst(func(a int) ReaderIOResult[string] { return Right("logged") }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = chainer(rioe) } } @@ -235,7 +236,7 @@ func BenchmarkChainFirst_Left(b *testing.B) { chainer := ChainFirst(func(a int) ReaderIOResult[string] { return Right("logged") }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = chainer(rioe) } } @@ -244,7 +245,7 @@ func BenchmarkFlatten_Right(b *testing.B) { nested := Right(Right(42)) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = Flatten(nested) } } @@ -253,28 +254,28 @@ func BenchmarkFlatten_Left(b *testing.B) { nested := Left[ReaderIOResult[int]](benchErr) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = Flatten(nested) } } // Benchmark applicative operations func BenchmarkMonadApSeq_RightRight(b *testing.B) { - fab := Right(func(a int) int { return a * 2 }) + fab := Right(N.Mul(2)) fa := Right(42) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = MonadApSeq(fab, fa) } } func BenchmarkMonadApSeq_RightLeft(b *testing.B) { - fab := Right(func(a int) int { return a * 2 }) + fab := Right(N.Mul(2)) fa := Left[int](benchErr) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = MonadApSeq(fab, fa) } } @@ -284,27 +285,27 @@ func BenchmarkMonadApSeq_LeftRight(b *testing.B) { fa := Right(42) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = MonadApSeq(fab, fa) } } func BenchmarkMonadApPar_RightRight(b *testing.B) { - fab := Right(func(a int) int { return a * 2 }) + fab := Right(N.Mul(2)) fa := Right(42) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = MonadApPar(fab, fa) } } func BenchmarkMonadApPar_RightLeft(b *testing.B) { - fab := Right(func(a int) int { return a * 2 }) + fab := Right(N.Mul(2)) fa := Left[int](benchErr) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = MonadApPar(fab, fa) } } @@ -314,30 +315,30 @@ func BenchmarkMonadApPar_LeftRight(b *testing.B) { fa := Right(42) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = MonadApPar(fab, fa) } } // Benchmark execution of applicative operations func BenchmarkExecuteApSeq_RightRight(b *testing.B) { - fab := Right(func(a int) int { return a * 2 }) + fab := Right(N.Mul(2)) fa := Right(42) rioe := MonadApSeq(fab, fa) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = rioe(benchCtx)() } } func BenchmarkExecuteApPar_RightRight(b *testing.B) { - fab := Right(func(a int) int { return a * 2 }) + fab := Right(N.Mul(2)) fa := Right(42) rioe := MonadApPar(fab, fa) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = rioe(benchCtx)() } } @@ -348,7 +349,7 @@ func BenchmarkAlt_RightRight(b *testing.B) { alternative := Alt(func() ReaderIOResult[int] { return Right(99) }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = alternative(rioe) } } @@ -358,7 +359,7 @@ func BenchmarkAlt_LeftRight(b *testing.B) { alternative := Alt(func() ReaderIOResult[int] { return Right(99) }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = alternative(rioe) } } @@ -368,7 +369,7 @@ func BenchmarkOrElse_Right(b *testing.B) { recover := OrElse(func(e error) ReaderIOResult[int] { return Right(0) }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = recover(rioe) } } @@ -378,7 +379,7 @@ func BenchmarkOrElse_Left(b *testing.B) { recover := OrElse(func(e error) ReaderIOResult[int] { return Right(0) }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = recover(rioe) } } @@ -389,7 +390,7 @@ func BenchmarkChainEitherK_Right(b *testing.B) { chainer := ChainEitherK(func(a int) Either[int] { return E.Right[error](a * 2) }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = chainer(rioe) } } @@ -399,7 +400,7 @@ func BenchmarkChainEitherK_Left(b *testing.B) { chainer := ChainEitherK(func(a int) Either[int] { return E.Right[error](a * 2) }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = chainer(rioe) } } @@ -409,7 +410,7 @@ func BenchmarkChainIOK_Right(b *testing.B) { chainer := ChainIOK(func(a int) func() int { return func() int { return a * 2 } }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = chainer(rioe) } } @@ -419,7 +420,7 @@ func BenchmarkChainIOK_Left(b *testing.B) { chainer := ChainIOK(func(a int) func() int { return func() int { return a * 2 } }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = chainer(rioe) } } @@ -429,7 +430,7 @@ func BenchmarkChainIOEitherK_Right(b *testing.B) { chainer := ChainIOEitherK(func(a int) IOEither[int] { return IOE.Of[error](a * 2) }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = chainer(rioe) } } @@ -439,7 +440,7 @@ func BenchmarkChainIOEitherK_Left(b *testing.B) { chainer := ChainIOEitherK(func(a int) IOEither[int] { return IOE.Of[error](a * 2) }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = chainer(rioe) } } @@ -447,7 +448,7 @@ func BenchmarkChainIOEitherK_Left(b *testing.B) { // Benchmark context operations func BenchmarkAsk(b *testing.B) { b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = Ask() } } @@ -455,7 +456,7 @@ func BenchmarkAsk(b *testing.B) { func BenchmarkDefer(b *testing.B) { gen := func() ReaderIOResult[int] { return Right(42) } b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = Defer(gen) } } @@ -463,7 +464,7 @@ func BenchmarkDefer(b *testing.B) { func BenchmarkMemoize(b *testing.B) { rioe := Right(42) b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = Memoize(rioe) } } @@ -472,14 +473,14 @@ func BenchmarkMemoize(b *testing.B) { func BenchmarkDelay_Construction(b *testing.B) { rioe := Right(42) b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = Delay[int](time.Millisecond)(rioe) } } func BenchmarkTimer_Construction(b *testing.B) { b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = Timer(time.Millisecond) } } @@ -490,7 +491,7 @@ func BenchmarkTryCatch_Success(b *testing.B) { return func() (int, error) { return 42, nil } } b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = TryCatch(f) } } @@ -500,7 +501,7 @@ func BenchmarkTryCatch_Error(b *testing.B) { return func() (int, error) { return 0, benchErr } } b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = TryCatch(f) } } @@ -512,7 +513,7 @@ func BenchmarkExecuteTryCatch_Success(b *testing.B) { rioe := TryCatch(f) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = rioe(benchCtx)() } } @@ -524,7 +525,7 @@ func BenchmarkExecuteTryCatch_Error(b *testing.B) { rioe := TryCatch(f) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = rioe(benchCtx)() } } @@ -534,10 +535,10 @@ func BenchmarkPipeline_Map_Right(b *testing.B) { rioe := Right(21) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = F.Pipe1( rioe, - Map(func(x int) int { return x * 2 }), + Map(N.Mul(2)), ) } } @@ -546,10 +547,10 @@ func BenchmarkPipeline_Map_Left(b *testing.B) { rioe := Left[int](benchErr) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = F.Pipe1( rioe, - Map(func(x int) int { return x * 2 }), + Map(N.Mul(2)), ) } } @@ -558,7 +559,7 @@ func BenchmarkPipeline_Chain_Right(b *testing.B) { rioe := Right(21) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = F.Pipe1( rioe, Chain(func(x int) ReaderIOResult[int] { return Right(x * 2) }), @@ -570,7 +571,7 @@ func BenchmarkPipeline_Chain_Left(b *testing.B) { rioe := Left[int](benchErr) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = F.Pipe1( rioe, Chain(func(x int) ReaderIOResult[int] { return Right(x * 2) }), @@ -582,12 +583,12 @@ func BenchmarkPipeline_Complex_Right(b *testing.B) { rioe := Right(10) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = F.Pipe3( rioe, - Map(func(x int) int { return x * 2 }), + Map(N.Mul(2)), Chain(func(x int) ReaderIOResult[int] { return Right(x + 1) }), - Map(func(x int) int { return x * 2 }), + Map(N.Mul(2)), ) } } @@ -596,12 +597,12 @@ func BenchmarkPipeline_Complex_Left(b *testing.B) { rioe := Left[int](benchErr) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchRIOE = F.Pipe3( rioe, - Map(func(x int) int { return x * 2 }), + Map(N.Mul(2)), Chain(func(x int) ReaderIOResult[int] { return Right(x + 1) }), - Map(func(x int) int { return x * 2 }), + Map(N.Mul(2)), ) } } @@ -609,13 +610,13 @@ func BenchmarkPipeline_Complex_Left(b *testing.B) { func BenchmarkExecutePipeline_Complex_Right(b *testing.B) { rioe := F.Pipe3( Right(10), - Map(func(x int) int { return x * 2 }), + Map(N.Mul(2)), Chain(func(x int) ReaderIOResult[int] { return Right(x + 1) }), - Map(func(x int) int { return x * 2 }), + Map(N.Mul(2)), ) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = rioe(benchCtx)() } } @@ -624,7 +625,7 @@ func BenchmarkExecutePipeline_Complex_Right(b *testing.B) { func BenchmarkDo(b *testing.B) { type State struct{ value int } b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = Do(State{}) } } @@ -642,7 +643,7 @@ func BenchmarkBind_Right(b *testing.B) { ) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = binder(initial) } } @@ -658,7 +659,7 @@ func BenchmarkLet_Right(b *testing.B) { ) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = letter(initial) } } @@ -674,7 +675,7 @@ func BenchmarkApS_Right(b *testing.B) { ) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = aps(initial) } } @@ -687,7 +688,7 @@ func BenchmarkTraverseArray_Empty(b *testing.B) { }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = traverser(arr) } } @@ -699,7 +700,7 @@ func BenchmarkTraverseArray_Small(b *testing.B) { }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = traverser(arr) } } @@ -714,7 +715,7 @@ func BenchmarkTraverseArray_Medium(b *testing.B) { }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = traverser(arr) } } @@ -726,7 +727,7 @@ func BenchmarkTraverseArraySeq_Small(b *testing.B) { }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = traverser(arr) } } @@ -738,7 +739,7 @@ func BenchmarkTraverseArrayPar_Small(b *testing.B) { }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = traverser(arr) } } @@ -751,7 +752,7 @@ func BenchmarkSequenceArray_Small(b *testing.B) { } b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = SequenceArray(arr) } } @@ -763,7 +764,7 @@ func BenchmarkExecuteTraverseArray_Small(b *testing.B) { })(arr) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = rioe(benchCtx)() } } @@ -775,7 +776,7 @@ func BenchmarkExecuteTraverseArraySeq_Small(b *testing.B) { })(arr) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = rioe(benchCtx)() } } @@ -787,7 +788,7 @@ func BenchmarkExecuteTraverseArrayPar_Small(b *testing.B) { })(arr) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = rioe(benchCtx)() } } @@ -800,7 +801,7 @@ func BenchmarkTraverseRecord_Small(b *testing.B) { }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = traverser(rec) } } @@ -813,7 +814,7 @@ func BenchmarkSequenceRecord_Small(b *testing.B) { } b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = SequenceRecord(rec) } } @@ -826,7 +827,7 @@ func BenchmarkWithResource_Success(b *testing.B) { b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = WithResource[int](acquire, release)(body) } } @@ -839,7 +840,7 @@ func BenchmarkExecuteWithResource_Success(b *testing.B) { b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = rioe(benchCtx)() } } @@ -852,7 +853,7 @@ func BenchmarkExecuteWithResource_ErrorInBody(b *testing.B) { b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = rioe(benchCtx)() } } @@ -865,13 +866,13 @@ func BenchmarkExecute_CanceledContext(b *testing.B) { b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = rioe(ctx)() } } func BenchmarkExecuteApPar_CanceledContext(b *testing.B) { - fab := Right(func(a int) int { return a * 2 }) + fab := Right(N.Mul(2)) fa := Right(42) rioe := MonadApPar(fab, fa) ctx, cancel := context.WithCancel(benchCtx) @@ -879,7 +880,7 @@ func BenchmarkExecuteApPar_CanceledContext(b *testing.B) { b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = rioe(ctx)() } } diff --git a/v2/context/readerioresult/reader_extended_test.go b/v2/context/readerioresult/reader_extended_test.go index d5e774a..3ebf774 100644 --- a/v2/context/readerioresult/reader_extended_test.go +++ b/v2/context/readerioresult/reader_extended_test.go @@ -26,6 +26,7 @@ import ( IOG "github.com/IBM/fp-go/v2/io" IOE "github.com/IBM/fp-go/v2/ioeither" M "github.com/IBM/fp-go/v2/monoid" + N "github.com/IBM/fp-go/v2/number" O "github.com/IBM/fp-go/v2/option" R "github.com/IBM/fp-go/v2/reader" "github.com/stretchr/testify/assert" @@ -77,27 +78,27 @@ func TestOf(t *testing.T) { func TestMonadMap(t *testing.T) { t.Run("Map over Right", func(t *testing.T) { - result := MonadMap(Of(5), func(x int) int { return x * 2 }) + result := MonadMap(Of(5), N.Mul(2)) assert.Equal(t, E.Right[error](10), result(context.Background())()) }) t.Run("Map over Left", func(t *testing.T) { err := errors.New("test error") - result := MonadMap(Left[int](err), func(x int) int { return x * 2 }) + result := MonadMap(Left[int](err), N.Mul(2)) assert.Equal(t, E.Left[int](err), result(context.Background())()) }) } func TestMap(t *testing.T) { t.Run("Map with success", func(t *testing.T) { - mapper := Map(func(x int) int { return x * 2 }) + mapper := Map(N.Mul(2)) result := mapper(Of(5)) assert.Equal(t, E.Right[error](10), result(context.Background())()) }) t.Run("Map with error", func(t *testing.T) { err := errors.New("test error") - mapper := Map(func(x int) int { return x * 2 }) + mapper := Map(N.Mul(2)) result := mapper(Left[int](err)) assert.Equal(t, E.Left[int](err), result(context.Background())()) }) @@ -182,7 +183,7 @@ func TestChainFirst(t *testing.T) { func TestMonadApSeq(t *testing.T) { t.Run("ApSeq with success", func(t *testing.T) { - fab := Of(func(x int) int { return x * 2 }) + fab := Of(N.Mul(2)) fa := Of(5) result := MonadApSeq(fab, fa) assert.Equal(t, E.Right[error](10), result(context.Background())()) @@ -198,7 +199,7 @@ func TestMonadApSeq(t *testing.T) { t.Run("ApSeq with error in value", func(t *testing.T) { err := errors.New("test error") - fab := Of(func(x int) int { return x * 2 }) + fab := Of(N.Mul(2)) fa := Left[int](err) result := MonadApSeq(fab, fa) assert.Equal(t, E.Left[int](err), result(context.Background())()) @@ -207,7 +208,7 @@ func TestMonadApSeq(t *testing.T) { func TestApSeq(t *testing.T) { fa := Of(5) - fab := Of(func(x int) int { return x * 2 }) + fab := Of(N.Mul(2)) result := MonadApSeq(fab, fa) assert.Equal(t, E.Right[error](10), result(context.Background())()) } @@ -215,7 +216,7 @@ func TestApSeq(t *testing.T) { func TestApPar(t *testing.T) { t.Run("ApPar with success", func(t *testing.T) { fa := Of(5) - fab := Of(func(x int) int { return x * 2 }) + fab := Of(N.Mul(2)) result := MonadApPar(fab, fa) assert.Equal(t, E.Right[error](10), result(context.Background())()) }) @@ -224,7 +225,7 @@ func TestApPar(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() fa := Of(5) - fab := Of(func(x int) int { return x * 2 }) + fab := Of(N.Mul(2)) result := MonadApPar(fab, fa) res := result(ctx)() assert.True(t, E.IsLeft(res)) @@ -587,14 +588,14 @@ func TestFlatten(t *testing.T) { } func TestMonadFlap(t *testing.T) { - fab := Of(func(x int) int { return x * 2 }) + fab := Of(N.Mul(2)) result := MonadFlap(fab, 5) assert.Equal(t, E.Right[error](10), result(context.Background())()) } func TestFlap(t *testing.T) { flapper := Flap[int](5) - result := flapper(Of(func(x int) int { return x * 2 })) + result := flapper(Of(N.Mul(2))) assert.Equal(t, E.Right[error](10), result(context.Background())()) } diff --git a/v2/di/token_test.go b/v2/di/token_test.go index a623e8e..6536a98 100644 --- a/v2/di/token_test.go +++ b/v2/di/token_test.go @@ -249,7 +249,7 @@ func TestMultiTokenStringRepresentation(t *testing.T) { // Benchmark tests func BenchmarkMakeToken(b *testing.B) { - for i := 0; i < b.N; i++ { + for b.Loop() { MakeToken[int]("BenchToken") } } @@ -259,13 +259,13 @@ func BenchmarkTokenUnerase(b *testing.B) { value := any(42) b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { token.Unerase(value) } } func BenchmarkMakeMultiToken(b *testing.B) { - for i := 0; i < b.N; i++ { + for b.Loop() { MakeMultiToken[int]("BenchMulti") } } diff --git a/v2/either/array_test.go b/v2/either/array_test.go index 3d4e8a2..3a517ac 100644 --- a/v2/either/array_test.go +++ b/v2/either/array_test.go @@ -4,16 +4,17 @@ import ( "fmt" "testing" + A "github.com/IBM/fp-go/v2/array" TST "github.com/IBM/fp-go/v2/internal/testing" "github.com/stretchr/testify/assert" ) func TestCompactArray(t *testing.T) { - ar := []Either[string, string]{ + ar := A.From( Of[string]("ok"), Left[string]("err"), Of[string]("ok"), - } + ) res := CompactArray(ar) assert.Equal(t, 2, len(res)) diff --git a/v2/either/either.go b/v2/either/either.go index b3097b2..db4dc4b 100644 --- a/v2/either/either.go +++ b/v2/either/either.go @@ -58,7 +58,7 @@ func FromIO[E any, IO ~func() A, A any](f IO) Either[E, A] { // // Example: // -// fab := either.Right[error](func(x int) int { return x * 2 }) +// fab := either.Right[error](N.Mul(2)) // fa := either.Right[error](21) // result := either.MonadAp(fab, fa) // Right(42) func MonadAp[B, E, A any](fab Either[E, func(a A) B], fa Either[E, A]) Either[E, B] { @@ -81,7 +81,7 @@ func Ap[B, E, A any](fa Either[E, A]) Operator[E, func(A) B, B] { // // result := either.MonadMap( // either.Right[error](21), -// func(x int) int { return x * 2 }, +// N.Mul(2), // ) // Right(42) // //go:inline diff --git a/v2/either/either_bench_test.go b/v2/either/either_bench_test.go index 96a98f7..c6a0c31 100644 --- a/v2/either/either_bench_test.go +++ b/v2/either/either_bench_test.go @@ -20,6 +20,7 @@ import ( "testing" F "github.com/IBM/fp-go/v2/function" + N "github.com/IBM/fp-go/v2/number" ) var ( @@ -33,21 +34,21 @@ var ( // Benchmark core constructors func BenchmarkLeft(b *testing.B) { b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = Left[int](errBench) } } func BenchmarkRight(b *testing.B) { b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = Right[error](42) } } func BenchmarkOf(b *testing.B) { b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = Of[error](42) } } @@ -57,7 +58,7 @@ func BenchmarkIsLeft(b *testing.B) { left := Left[int](errBench) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchBool = IsLeft(left) } } @@ -66,7 +67,7 @@ func BenchmarkIsRight(b *testing.B) { right := Right[error](42) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchBool = IsRight(right) } } @@ -75,10 +76,10 @@ func BenchmarkIsRight(b *testing.B) { func BenchmarkMonadFold_Right(b *testing.B) { right := Right[error](42) onLeft := func(e error) int { return 0 } - onRight := func(a int) int { return a * 2 } + onRight := N.Mul(2) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchInt = MonadFold(right, onLeft, onRight) } } @@ -86,10 +87,10 @@ func BenchmarkMonadFold_Right(b *testing.B) { func BenchmarkMonadFold_Left(b *testing.B) { left := Left[int](errBench) onLeft := func(e error) int { return 0 } - onRight := func(a int) int { return a * 2 } + onRight := N.Mul(2) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchInt = MonadFold(left, onLeft, onRight) } } @@ -98,11 +99,11 @@ func BenchmarkFold_Right(b *testing.B) { right := Right[error](42) folder := Fold( func(e error) int { return 0 }, - func(a int) int { return a * 2 }, + N.Mul(2), ) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchInt = folder(right) } } @@ -111,11 +112,11 @@ func BenchmarkFold_Left(b *testing.B) { left := Left[int](errBench) folder := Fold( func(e error) int { return 0 }, - func(a int) int { return a * 2 }, + N.Mul(2), ) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchInt = folder(left) } } @@ -125,7 +126,7 @@ func BenchmarkUnwrap_Right(b *testing.B) { right := Right[error](42) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchInt, _ = Unwrap(right) } } @@ -134,7 +135,7 @@ func BenchmarkUnwrap_Left(b *testing.B) { left := Left[int](errBench) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchInt, _ = Unwrap(left) } } @@ -143,7 +144,7 @@ func BenchmarkUnwrapError_Right(b *testing.B) { right := Right[error](42) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchInt, _ = UnwrapError(right) } } @@ -152,7 +153,7 @@ func BenchmarkUnwrapError_Left(b *testing.B) { left := Left[int](errBench) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchInt, _ = UnwrapError(left) } } @@ -160,40 +161,40 @@ func BenchmarkUnwrapError_Left(b *testing.B) { // Benchmark functor operations func BenchmarkMonadMap_Right(b *testing.B) { right := Right[error](42) - mapper := func(a int) int { return a * 2 } + mapper := N.Mul(2) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = MonadMap(right, mapper) } } func BenchmarkMonadMap_Left(b *testing.B) { left := Left[int](errBench) - mapper := func(a int) int { return a * 2 } + mapper := N.Mul(2) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = MonadMap(left, mapper) } } func BenchmarkMap_Right(b *testing.B) { right := Right[error](42) - mapper := Map[error](func(a int) int { return a * 2 }) + mapper := Map[error](N.Mul(2)) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = mapper(right) } } func BenchmarkMap_Left(b *testing.B) { left := Left[int](errBench) - mapper := Map[error](func(a int) int { return a * 2 }) + mapper := Map[error](N.Mul(2)) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = mapper(left) } } @@ -203,7 +204,7 @@ func BenchmarkMapLeft_Right(b *testing.B) { mapper := MapLeft[int](error.Error) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = mapper(right) } } @@ -213,7 +214,7 @@ func BenchmarkMapLeft_Left(b *testing.B) { mapper := MapLeft[int](error.Error) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = mapper(left) } } @@ -226,7 +227,7 @@ func BenchmarkBiMap_Right(b *testing.B) { ) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = mapper(right) } } @@ -239,7 +240,7 @@ func BenchmarkBiMap_Left(b *testing.B) { ) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = mapper(left) } } @@ -250,7 +251,7 @@ func BenchmarkMonadChain_Right(b *testing.B) { chainer := func(a int) Either[error, int] { return Right[error](a * 2) } b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = MonadChain(right, chainer) } } @@ -260,7 +261,7 @@ func BenchmarkMonadChain_Left(b *testing.B) { chainer := func(a int) Either[error, int] { return Right[error](a * 2) } b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = MonadChain(left, chainer) } } @@ -270,7 +271,7 @@ func BenchmarkChain_Right(b *testing.B) { chainer := Chain(func(a int) Either[error, int] { return Right[error](a * 2) }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = chainer(right) } } @@ -280,7 +281,7 @@ func BenchmarkChain_Left(b *testing.B) { chainer := Chain(func(a int) Either[error, int] { return Right[error](a * 2) }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = chainer(left) } } @@ -290,7 +291,7 @@ func BenchmarkChainFirst_Right(b *testing.B) { chainer := ChainFirst(func(a int) Either[error, string] { return Right[error]("logged") }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = chainer(right) } } @@ -300,7 +301,7 @@ func BenchmarkChainFirst_Left(b *testing.B) { chainer := ChainFirst(func(a int) Either[error, string] { return Right[error]("logged") }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = chainer(left) } } @@ -309,7 +310,7 @@ func BenchmarkFlatten_Right(b *testing.B) { nested := Right[error](Right[error](42)) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = Flatten(nested) } } @@ -318,28 +319,28 @@ func BenchmarkFlatten_Left(b *testing.B) { nested := Left[Either[error, int]](errBench) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = Flatten(nested) } } // Benchmark applicative operations func BenchmarkMonadAp_RightRight(b *testing.B) { - fab := Right[error](func(a int) int { return a * 2 }) + fab := Right[error](N.Mul(2)) fa := Right[error](42) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = MonadAp(fab, fa) } } func BenchmarkMonadAp_RightLeft(b *testing.B) { - fab := Right[error](func(a int) int { return a * 2 }) + fab := Right[error](N.Mul(2)) fa := Left[int](errBench) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = MonadAp(fab, fa) } } @@ -349,18 +350,18 @@ func BenchmarkMonadAp_LeftRight(b *testing.B) { fa := Right[error](42) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = MonadAp(fab, fa) } } func BenchmarkAp_RightRight(b *testing.B) { - fab := Right[error](func(a int) int { return a * 2 }) + fab := Right[error](N.Mul(2)) fa := Right[error](42) ap := Ap[int](fa) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = ap(fab) } } @@ -371,7 +372,7 @@ func BenchmarkAlt_RightRight(b *testing.B) { alternative := Alt(func() Either[error, int] { return Right[error](99) }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = alternative(right) } } @@ -381,7 +382,7 @@ func BenchmarkAlt_LeftRight(b *testing.B) { alternative := Alt(func() Either[error, int] { return Right[error](99) }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = alternative(left) } } @@ -391,7 +392,7 @@ func BenchmarkOrElse_Right(b *testing.B) { recover := OrElse(func(e error) Either[error, int] { return Right[error](0) }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = recover(right) } } @@ -401,7 +402,7 @@ func BenchmarkOrElse_Left(b *testing.B) { recover := OrElse(func(e error) Either[error, int] { return Right[error](0) }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = recover(left) } } @@ -410,7 +411,7 @@ func BenchmarkOrElse_Left(b *testing.B) { func BenchmarkTryCatch_Success(b *testing.B) { onThrow := func(err error) error { return err } b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = TryCatch(42, nil, onThrow) } } @@ -418,21 +419,21 @@ func BenchmarkTryCatch_Success(b *testing.B) { func BenchmarkTryCatch_Error(b *testing.B) { onThrow := func(err error) error { return err } b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = TryCatch(0, errBench, onThrow) } } func BenchmarkTryCatchError_Success(b *testing.B) { b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = TryCatchError(42, nil) } } func BenchmarkTryCatchError_Error(b *testing.B) { b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = TryCatchError(0, errBench) } } @@ -441,7 +442,7 @@ func BenchmarkSwap_Right(b *testing.B) { right := Right[error](42) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = Swap(right) } } @@ -450,7 +451,7 @@ func BenchmarkSwap_Left(b *testing.B) { left := Left[int](errBench) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = Swap(left) } } @@ -460,7 +461,7 @@ func BenchmarkGetOrElse_Right(b *testing.B) { getter := GetOrElse(func(e error) int { return 0 }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchInt = getter(right) } } @@ -470,7 +471,7 @@ func BenchmarkGetOrElse_Left(b *testing.B) { getter := GetOrElse(func(e error) int { return 0 }) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchInt = getter(left) } } @@ -480,10 +481,10 @@ func BenchmarkPipeline_Map_Right(b *testing.B) { right := Right[error](21) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = F.Pipe1( right, - Map[error](func(x int) int { return x * 2 }), + Map[error](N.Mul(2)), ) } } @@ -492,10 +493,10 @@ func BenchmarkPipeline_Map_Left(b *testing.B) { left := Left[int](errBench) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = F.Pipe1( left, - Map[error](func(x int) int { return x * 2 }), + Map[error](N.Mul(2)), ) } } @@ -504,7 +505,7 @@ func BenchmarkPipeline_Chain_Right(b *testing.B) { right := Right[error](21) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = F.Pipe1( right, Chain(func(x int) Either[error, int] { return Right[error](x * 2) }), @@ -516,7 +517,7 @@ func BenchmarkPipeline_Chain_Left(b *testing.B) { left := Left[int](errBench) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = F.Pipe1( left, Chain(func(x int) Either[error, int] { return Right[error](x * 2) }), @@ -528,12 +529,12 @@ func BenchmarkPipeline_Complex_Right(b *testing.B) { right := Right[error](10) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = F.Pipe3( right, - Map[error](func(x int) int { return x * 2 }), + Map[error](N.Mul(2)), Chain(func(x int) Either[error, int] { return Right[error](x + 1) }), - Map[error](func(x int) int { return x * 2 }), + Map[error](N.Mul(2)), ) } } @@ -542,12 +543,12 @@ func BenchmarkPipeline_Complex_Left(b *testing.B) { left := Left[int](errBench) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = F.Pipe3( left, - Map[error](func(x int) int { return x * 2 }), + Map[error](N.Mul(2)), Chain(func(x int) Either[error, int] { return Right[error](x + 1) }), - Map[error](func(x int) int { return x * 2 }), + Map[error](N.Mul(2)), ) } } @@ -559,7 +560,7 @@ func BenchmarkMonadSequence2_RightRight(b *testing.B) { f := func(a, b int) Either[error, int] { return Right[error](a + b) } b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = MonadSequence2(e1, e2, f) } } @@ -570,7 +571,7 @@ func BenchmarkMonadSequence2_LeftRight(b *testing.B) { f := func(a, b int) Either[error, int] { return Right[error](a + b) } b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = MonadSequence2(e1, e2, f) } } @@ -582,7 +583,7 @@ func BenchmarkMonadSequence3_RightRightRight(b *testing.B) { f := func(a, b, c int) Either[error, int] { return Right[error](a + b + c) } b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchResult = MonadSequence3(e1, e2, e3, f) } } @@ -591,7 +592,7 @@ func BenchmarkMonadSequence3_RightRightRight(b *testing.B) { func BenchmarkDo(b *testing.B) { type State struct{ value int } b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = Do[error](State{}) } } @@ -609,7 +610,7 @@ func BenchmarkBind_Right(b *testing.B) { ) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = binder(initial) } } @@ -625,7 +626,7 @@ func BenchmarkLet_Right(b *testing.B) { ) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = letter(initial) } } @@ -635,7 +636,7 @@ func BenchmarkString_Right(b *testing.B) { right := Right[error](42) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchString = right.String() } } @@ -644,7 +645,7 @@ func BenchmarkString_Left(b *testing.B) { left := Left[int](errBench) b.ResetTimer() b.ReportAllocs() - for i := 0; i < b.N; i++ { + for b.Loop() { benchString = left.String() } } diff --git a/v2/either/either_test.go b/v2/either/either_test.go index d2cb2c6..049d2ee 100644 --- a/v2/either/either_test.go +++ b/v2/either/either_test.go @@ -66,7 +66,7 @@ func TestUnwrapError(t *testing.T) { func TestReduce(t *testing.T) { - s := S.Semigroup() + s := S.Semigroup assert.Equal(t, "foobar", F.Pipe1(Right[string]("bar"), Reduce[string](s.Concat, "foo"))) assert.Equal(t, "foo", F.Pipe1(Left[string]("bar"), Reduce[string](s.Concat, "foo"))) diff --git a/v2/either/logger.go b/v2/either/logger.go index 0b55dbc..7b56e1d 100644 --- a/v2/either/logger.go +++ b/v2/either/logger.go @@ -46,7 +46,7 @@ func _log[E, A any](left func(string, ...any), right func(string, ...any), prefi // result := F.Pipe2( // either.Right[error](42), // logger("Processing"), -// either.Map(func(x int) int { return x * 2 }), +// either.Map(N.Mul(2)), // ) // // Logs: "Processing: 42" // // result is Right(84) diff --git a/v2/either/validation.go b/v2/either/validation.go new file mode 100644 index 0000000..17bf14b --- /dev/null +++ b/v2/either/validation.go @@ -0,0 +1,142 @@ +// Copyright (c) 2025 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 either + +import ( + F "github.com/IBM/fp-go/v2/function" + S "github.com/IBM/fp-go/v2/semigroup" +) + +// MonadApV is the applicative validation functor that combines errors using a semigroup. +// +// Unlike the standard [MonadAp] which short-circuits on the first Left (error), +// MonadApV accumulates all errors using the provided semigroup's Concat operation. +// This is particularly useful for validation scenarios where you want to collect +// all validation errors rather than stopping at the first one. +// +// The function takes a semigroup for combining errors and returns a function that +// applies a wrapped function to a wrapped value, accumulating errors if both are Left. +// +// Behavior: +// - If both fab and fa are Left, combines their errors using sg.Concat +// - If only fab is Left, returns Left with fab's error +// - If only fa is Left, returns Left with fa's error +// - If both are Right, applies the function and returns Right with the result +// +// Type Parameters: +// - B: The result type after applying the function +// - E: The error type (must support the semigroup operation) +// - A: The input type to the function +// +// Parameters: +// - sg: A semigroup that defines how to combine two error values +// +// Returns: +// - A function that takes a wrapped function and a wrapped value, returning +// Either[E, B] with accumulated errors or the computed result +// +// Example: +// +// // Define a semigroup that concatenates error messages +// errorSemigroup := semigroup.MakeSemigroup(func(e1, e2 string) string { +// return e1 + "; " + e2 +// }) +// +// // Create the validation applicative +// applyV := either.MonadApV[int](errorSemigroup) +// +// // Both are errors - errors get combined +// fab := either.Left[func(int) int]("error1") +// fa := either.Left[int]("error2") +// result := applyV(fab, fa) // Left("error1; error2") +// +// // One error - returns that error +// fab2 := either.Right[string](N.Mul(2)) +// fa2 := either.Left[int]("validation failed") +// result2 := applyV(fab2, fa2) // Left("validation failed") +// +// // Both success - applies function +// fab3 := either.Right[string](N.Mul(2)) +// fa3 := either.Right[string](21) +// result3 := applyV(fab3, fa3) // Right(42) +func MonadApV[B, E, A any](sg S.Semigroup[E]) func(fab Either[E, func(a A) B], fa Either[E, A]) Either[E, B] { + c := F.Bind2of2(sg.Concat) + return func(fab Either[E, func(a A) B], fa Either[E, A]) Either[E, B] { + return MonadFold(fab, func(eab E) Either[E, B] { + return MonadFold(fa, F.Flow2(c(eab), Left[B]), F.Constant1[A](Left[B](eab))) + }, func(ab func(A) B) Either[E, B] { + return MonadFold(fa, Left[B, E], F.Flow2(ab, Right[E, B])) + }) + } +} + +// ApV is the curried version of [MonadApV] that combines errors using a semigroup. +// +// This function provides a more convenient API for validation scenarios by currying +// the arguments. It first takes the value to validate, then returns a function that +// takes the validation function. This allows for a more natural composition style. +// +// Like [MonadApV], this accumulates all errors using the provided semigroup instead +// of short-circuiting on the first error. This is the key difference from the +// standard [Ap] function. +// +// Type Parameters: +// - B: The result type after applying the function +// - E: The error type (must support the semigroup operation) +// - A: The input type to the function +// +// Parameters: +// - sg: A semigroup that defines how to combine two error values +// +// Returns: +// - A function that takes a value Either[E, A] and returns an Operator that +// applies validation functions while accumulating errors +// +// Example: +// +// // Define a semigroup for combining validation errors +// type ValidationError struct { +// Errors []string +// } +// errorSemigroup := semigroup.MakeSemigroup(func(e1, e2 ValidationError) ValidationError { +// return ValidationError{Errors: append(e1.Errors, e2.Errors...)} +// }) +// +// // Create validators +// validatePositive := func(x int) either.Either[ValidationError, int] { +// if x > 0 { +// return either.Right[ValidationError](x) +// } +// return either.Left[int](ValidationError{Errors: []string{"must be positive"}}) +// } +// +// // Use ApV for validation +// applyValidation := either.ApV[int](errorSemigroup) +// value := either.Left[int](ValidationError{Errors: []string{"invalid input"}}) +// validator := either.Left[func(int) int](ValidationError{Errors: []string{"invalid validator"}}) +// +// result := applyValidation(value)(validator) +// // Left(ValidationError{Errors: []string{"invalid validator", "invalid input"}}) +func ApV[B, E, A any](sg S.Semigroup[E]) func(fa Either[E, A]) Operator[E, func(A) B, B] { + c := F.Bind2of2(sg.Concat) + return func(fa Either[E, A]) Operator[E, func(A) B, B] { + return Fold(func(eab E) Either[E, B] { + return MonadFold(fa, F.Flow2(c(eab), Left[B]), F.Constant1[A](Left[B](eab))) + }, func(ab func(A) B) Either[E, B] { + return MonadFold(fa, Left[B, E], F.Flow2(ab, Right[E, B])) + }) + } +} diff --git a/v2/either/validation_test.go b/v2/either/validation_test.go new file mode 100644 index 0000000..39d5cc8 --- /dev/null +++ b/v2/either/validation_test.go @@ -0,0 +1,381 @@ +// Copyright (c) 2025 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 either + +import ( + "testing" + + F "github.com/IBM/fp-go/v2/function" + N "github.com/IBM/fp-go/v2/number" + S "github.com/IBM/fp-go/v2/semigroup" + "github.com/stretchr/testify/assert" +) + +// TestMonadApV_BothRight tests MonadApV when both function and value are Right +func TestMonadApV_BothRight(t *testing.T) { + // Create a semigroup for string concatenation + sg := S.MakeSemigroup(func(a, b string) string { + return a + "; " + b + }) + + // Create the validation applicative + applyV := MonadApV[int, string, int](sg) + + // Both are Right - should apply function + fab := Right[string](N.Mul(2)) + fa := Right[string](21) + + result := applyV(fab, fa) + + assert.True(t, IsRight(result)) + assert.Equal(t, Right[string](42), result) +} + +// TestMonadApV_BothLeft tests MonadApV when both function and value are Left +func TestMonadApV_BothLeft(t *testing.T) { + // Create a semigroup for string concatenation + sg := S.MakeSemigroup(func(a, b string) string { + return a + "; " + b + }) + + // Create the validation applicative + applyV := MonadApV[int, string, int](sg) + + // Both are Left - should combine errors + fab := Left[func(int) int]("error1") + fa := Left[int]("error2") + + result := applyV(fab, fa) + + assert.True(t, IsLeft(result)) + // When both are Left, errors are combined as: fa error + fab error + assert.Equal(t, Left[int]("error2; error1"), result) +} + +// TestMonadApV_LeftFunction tests MonadApV when function is Left and value is Right +func TestMonadApV_LeftFunction(t *testing.T) { + // Create a semigroup for string concatenation + sg := S.MakeSemigroup(func(a, b string) string { + return a + "; " + b + }) + + // Create the validation applicative + applyV := MonadApV[int, string, int](sg) + + // Function is Left, value is Right - should return function's error + fab := Left[func(int) int]("function error") + fa := Right[string](21) + + result := applyV(fab, fa) + + assert.True(t, IsLeft(result)) + assert.Equal(t, Left[int]("function error"), result) +} + +// TestMonadApV_LeftValue tests MonadApV when function is Right and value is Left +func TestMonadApV_LeftValue(t *testing.T) { + // Create a semigroup for string concatenation + sg := S.MakeSemigroup(func(a, b string) string { + return a + "; " + b + }) + + // Create the validation applicative + applyV := MonadApV[int, string, int](sg) + + // Function is Right, value is Left - should return value's error + fab := Right[string](N.Mul(2)) + fa := Left[int]("value error") + + result := applyV(fab, fa) + + assert.True(t, IsLeft(result)) + assert.Equal(t, Left[int]("value error"), result) +} + +// TestMonadApV_WithSliceSemigroup tests MonadApV with a slice-based semigroup +func TestMonadApV_WithSliceSemigroup(t *testing.T) { + // Create a semigroup that concatenates slices + sg := S.MakeSemigroup(func(a, b []string) []string { + return append(a, b...) + }) + + // Create the validation applicative + applyV := MonadApV[string, []string, string](sg) + + // Both are Left with slice errors + fab := Left[func(string) string]([]string{"error1", "error2"}) + fa := Left[string]([]string{"error3", "error4"}) + + result := applyV(fab, fa) + + assert.True(t, IsLeft(result)) + // When both are Left, errors are combined as: fa errors + fab errors + expected := Left[string]([]string{"error3", "error4", "error1", "error2"}) + assert.Equal(t, expected, result) +} + +// TestMonadApV_ComplexFunction tests MonadApV with a more complex function +func TestMonadApV_ComplexFunction(t *testing.T) { + // Create a semigroup for string concatenation + sg := S.MakeSemigroup(func(a, b string) string { + return a + " | " + b + }) + + // Create the validation applicative + applyV := MonadApV[string, string, int](sg) + + // Test with a function that transforms the value + fab := Right[string](func(x int) string { + if x > 0 { + return "positive" + } + return "non-positive" + }) + fa := Right[string](42) + + result := applyV(fab, fa) + + assert.True(t, IsRight(result)) + assert.Equal(t, Right[string]("positive"), result) +} + +// TestApV_BothRight tests ApV when both function and value are Right +func TestApV_BothRight(t *testing.T) { + // Create a semigroup for string concatenation + sg := S.MakeSemigroup(func(a, b string) string { + return a + "; " + b + }) + + // Create the validation applicative + applyV := ApV[int, string, int](sg) + + // Both are Right - should apply function + fa := Right[string](21) + fab := Right[string](N.Mul(2)) + + result := applyV(fa)(fab) + + assert.True(t, IsRight(result)) + assert.Equal(t, Right[string](42), result) +} + +// TestApV_BothLeft tests ApV when both function and value are Left +func TestApV_BothLeft(t *testing.T) { + // Create a semigroup for string concatenation + sg := S.MakeSemigroup(func(a, b string) string { + return a + "; " + b + }) + + // Create the validation applicative + applyV := ApV[int, string, int](sg) + + // Both are Left - should combine errors + fa := Left[int]("error2") + fab := Left[func(int) int]("error1") + + result := applyV(fa)(fab) + + assert.True(t, IsLeft(result)) + // When both are Left, errors are combined as: fa error + fab error + assert.Equal(t, Left[int]("error2; error1"), result) +} + +// TestApV_LeftFunction tests ApV when function is Left and value is Right +func TestApV_LeftFunction(t *testing.T) { + // Create a semigroup for string concatenation + sg := S.MakeSemigroup(func(a, b string) string { + return a + "; " + b + }) + + // Create the validation applicative + applyV := ApV[int, string, int](sg) + + // Function is Left, value is Right - should return function's error + fa := Right[string](21) + fab := Left[func(int) int]("function error") + + result := applyV(fa)(fab) + + assert.True(t, IsLeft(result)) + assert.Equal(t, Left[int]("function error"), result) +} + +// TestApV_LeftValue tests ApV when function is Right and value is Left +func TestApV_LeftValue(t *testing.T) { + // Create a semigroup for string concatenation + sg := S.MakeSemigroup(func(a, b string) string { + return a + "; " + b + }) + + // Create the validation applicative + applyV := ApV[int, string, int](sg) + + // Function is Right, value is Left - should return value's error + fa := Left[int]("value error") + fab := Right[string](N.Mul(2)) + + result := applyV(fa)(fab) + + assert.True(t, IsLeft(result)) + assert.Equal(t, Left[int]("value error"), result) +} + +// TestApV_Composition tests ApV with function composition +func TestApV_Composition(t *testing.T) { + // Create a semigroup for string concatenation + sg := S.MakeSemigroup(func(a, b string) string { + return a + " & " + b + }) + + // Create the validation applicative + applyV := ApV[string, string, int](sg) + + // Test composition with pipe + fa := Right[string](10) + fab := Right[string](func(x int) string { + return F.Pipe1(x, func(n int) string { + if n >= 10 { + return "large" + } + return "small" + }) + }) + + result := F.Pipe1(fa, applyV)(fab) + + assert.True(t, IsRight(result)) + assert.Equal(t, Right[string]("large"), result) +} + +// TestApV_WithStructSemigroup tests ApV with a custom struct semigroup +func TestApV_WithStructSemigroup(t *testing.T) { + type ValidationErrors struct { + Errors []string + } + + // Create a semigroup that combines validation errors + sg := S.MakeSemigroup(func(a, b ValidationErrors) ValidationErrors { + return ValidationErrors{ + Errors: append(append([]string{}, a.Errors...), b.Errors...), + } + }) + + // Create the validation applicative + applyV := ApV[int, ValidationErrors, int](sg) + + // Both are Left with validation errors + fa := Left[int](ValidationErrors{Errors: []string{"field1: required"}}) + fab := Left[func(int) int](ValidationErrors{Errors: []string{"field2: invalid"}}) + + result := applyV(fa)(fab) + + assert.True(t, IsLeft(result)) + // When both are Left, errors are combined as: fa errors + fab errors + expected := Left[int](ValidationErrors{ + Errors: []string{"field1: required", "field2: invalid"}, + }) + assert.Equal(t, expected, result) +} + +// TestApV_MultipleValidations tests ApV with multiple validation steps +func TestApV_MultipleValidations(t *testing.T) { + // Create a semigroup for string concatenation + sg := S.MakeSemigroup(func(a, b string) string { + return a + ", " + b + }) + + // Create the validation applicative + applyV := ApV[int, string, int](sg) + + // Simulate multiple validation failures + validation1 := Left[int]("age must be positive") + validation2 := Left[func(int) int]("name is required") + + result := applyV(validation1)(validation2) + + assert.True(t, IsLeft(result)) + // When both are Left, errors are combined as: validation1 error + validation2 error + assert.Equal(t, Left[int]("age must be positive, name is required"), result) +} + +// TestMonadApV_DifferentTypes tests MonadApV with different input and output types +func TestMonadApV_DifferentTypes(t *testing.T) { + // Create a semigroup for string concatenation + sg := S.MakeSemigroup(func(a, b string) string { + return a + " + " + b + }) + + // Create the validation applicative + applyV := MonadApV[string, string, int](sg) + + // Function converts int to string + fab := Right[string](func(x int) string { + return F.Pipe1(x, func(n int) string { + if n == 0 { + return "zero" + } else if n > 0 { + return "positive" + } + return "negative" + }) + }) + fa := Right[string](-5) + + result := applyV(fab, fa) + + assert.True(t, IsRight(result)) + assert.Equal(t, Right[string]("negative"), result) +} + +// TestApV_FirstSemigroup tests ApV with First semigroup (always returns first error) +func TestApV_FirstSemigroup(t *testing.T) { + // Use First semigroup which always returns the first value + sg := S.First[string]() + + // Create the validation applicative + applyV := ApV[int, string, int](sg) + + // Both are Left - should return first error + fa := Left[int]("error2") + fab := Left[func(int) int]("error1") + + result := applyV(fa)(fab) + + assert.True(t, IsLeft(result)) + // First semigroup returns the first value, which is fa's error + assert.Equal(t, Left[int]("error2"), result) +} + +// TestApV_LastSemigroup tests ApV with Last semigroup (always returns last error) +func TestApV_LastSemigroup(t *testing.T) { + // Use Last semigroup which always returns the last value + sg := S.Last[string]() + + // Create the validation applicative + applyV := ApV[int, string, int](sg) + + // Both are Left - should return last error + fa := Left[int]("error2") + fab := Left[func(int) int]("error1") + + result := applyV(fa)(fab) + + assert.True(t, IsLeft(result)) + // Last semigroup returns the last value, which is fab's error + assert.Equal(t, Left[int]("error1"), result) +} + +// Made with Bob diff --git a/v2/endomorphism/doc.go b/v2/endomorphism/doc.go index bd44436..9d6ea40 100644 --- a/v2/endomorphism/doc.go +++ b/v2/endomorphism/doc.go @@ -36,7 +36,7 @@ // ) // // // Define some endomorphisms -// double := func(x int) int { return x * 2 } +// double := N.Mul(2) // increment := func(x int) int { return x + 1 } // // // Compose them (RIGHT-TO-LEFT execution) @@ -62,7 +62,7 @@ // // // Combine multiple endomorphisms (RIGHT-TO-LEFT execution) // combined := M.ConcatAll(monoid)( -// func(x int) int { return x * 2 }, // applied third +// N.Mul(2), // applied third // func(x int) int { return x + 1 }, // applied second // func(x int) int { return x * 3 }, // applied first // ) @@ -74,7 +74,7 @@ // MonadChain executes LEFT-TO-RIGHT, unlike Compose: // // // Chain allows sequencing of endomorphisms (LEFT-TO-RIGHT) -// f := func(x int) int { return x * 2 } +// f := N.Mul(2) // g := func(x int) int { return x + 1 } // chained := endomorphism.MonadChain(f, g) // f first, then g // result := chained(5) // (5 * 2) + 1 = 11 @@ -83,7 +83,7 @@ // // The key difference between Compose and Chain/MonadChain is execution order: // -// double := func(x int) int { return x * 2 } +// double := N.Mul(2) // increment := func(x int) int { return x + 1 } // // // Compose: RIGHT-TO-LEFT (mathematical composition) diff --git a/v2/endomorphism/endo.go b/v2/endomorphism/endo.go index 4039b31..4577584 100644 --- a/v2/endomorphism/endo.go +++ b/v2/endomorphism/endo.go @@ -37,7 +37,7 @@ import ( // // Example: // -// double := func(x int) int { return x * 2 } +// double := N.Mul(2) // increment := func(x int) int { return x + 1 } // result := endomorphism.MonadAp(double, increment) // Composes: double ∘ increment // // result(5) = double(increment(5)) = double(6) = 12 @@ -64,7 +64,7 @@ func MonadAp[A any](fab Endomorphism[A], fa Endomorphism[A]) Endomorphism[A] { // // increment := func(x int) int { return x + 1 } // applyIncrement := endomorphism.Ap(increment) -// double := func(x int) int { return x * 2 } +// double := N.Mul(2) // composed := applyIncrement(double) // double ∘ increment // // composed(5) = double(increment(5)) = double(6) = 12 func Ap[A any](fa Endomorphism[A]) Operator[A] { @@ -91,7 +91,7 @@ func Ap[A any](fa Endomorphism[A]) Operator[A] { // // Example: // -// double := func(x int) int { return x * 2 } +// double := N.Mul(2) // increment := func(x int) int { return x + 1 } // // // MonadCompose executes RIGHT-TO-LEFT: increment first, then double @@ -123,7 +123,7 @@ func MonadCompose[A any](f, g Endomorphism[A]) Endomorphism[A] { // // Example: // -// double := func(x int) int { return x * 2 } +// double := N.Mul(2) // increment := func(x int) int { return x + 1 } // mapped := endomorphism.MonadMap(double, increment) // // mapped(5) = double(increment(5)) = double(6) = 12 @@ -153,7 +153,7 @@ func MonadMap[A any](f, g Endomorphism[A]) Endomorphism[A] { // // increment := func(x int) int { return x + 1 } // composeWithIncrement := endomorphism.Compose(increment) -// double := func(x int) int { return x * 2 } +// double := N.Mul(2) // // // Composes double with increment (RIGHT-TO-LEFT: increment first, then double) // composed := composeWithIncrement(double) @@ -186,7 +186,7 @@ func Compose[A any](g Endomorphism[A]) Operator[A] { // // Example: // -// double := func(x int) int { return x * 2 } +// double := N.Mul(2) // mapDouble := endomorphism.Map(double) // increment := func(x int) int { return x + 1 } // mapped := mapDouble(increment) @@ -215,7 +215,7 @@ func Map[A any](f Endomorphism[A]) Operator[A] { // // Example: // -// double := func(x int) int { return x * 2 } +// double := N.Mul(2) // increment := func(x int) int { return x + 1 } // // // MonadChain executes LEFT-TO-RIGHT: double first, then increment @@ -243,7 +243,7 @@ func MonadChain[A any](ma Endomorphism[A], f Endomorphism[A]) Endomorphism[A] { // // Example: // -// double := func(x int) int { return x * 2 } +// double := N.Mul(2) // log := func(x int) int { fmt.Println(x); return x } // chained := endomorphism.MonadChainFirst(double, log) // result := chained(5) // Prints 10, returns 10 @@ -269,7 +269,7 @@ func MonadChainFirst[A any](ma Endomorphism[A], f Endomorphism[A]) Endomorphism[ // // log := func(x int) int { fmt.Println(x); return x } // chainLog := endomorphism.ChainFirst(log) -// double := func(x int) int { return x * 2 } +// double := N.Mul(2) // chained := chainLog(double) // result := chained(5) // Prints 10, returns 10 func ChainFirst[A any](f Endomorphism[A]) Operator[A] { @@ -296,7 +296,7 @@ func ChainFirst[A any](f Endomorphism[A]) Operator[A] { // // increment := func(x int) int { return x + 1 } // chainWithIncrement := endomorphism.Chain(increment) -// double := func(x int) int { return x * 2 } +// double := N.Mul(2) // // // Chains double (first) with increment (second) // chained := chainWithIncrement(double) diff --git a/v2/endomorphism/endomorphism_test.go b/v2/endomorphism/endomorphism_test.go index 78abd04..ac2b97c 100644 --- a/v2/endomorphism/endomorphism_test.go +++ b/v2/endomorphism/endomorphism_test.go @@ -19,6 +19,7 @@ import ( "testing" M "github.com/IBM/fp-go/v2/monoid" + N "github.com/IBM/fp-go/v2/number" S "github.com/IBM/fp-go/v2/semigroup" "github.com/stretchr/testify/assert" ) @@ -204,7 +205,7 @@ func TestCompose(t *testing.T) { // TestMonadComposeVsCompose demonstrates the relationship between MonadCompose and Compose func TestMonadComposeVsCompose(t *testing.T) { - double := func(x int) int { return x * 2 } + double := N.Mul(2) increment := func(x int) int { return x + 1 } // MonadCompose takes both functions at once @@ -448,7 +449,7 @@ func TestOperatorType(t *testing.T) { func BenchmarkCompose(b *testing.B) { composed := MonadCompose(double, increment) b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = composed(5) } } @@ -456,7 +457,7 @@ func BenchmarkCompose(b *testing.B) { // BenchmarkMonoidConcatAll benchmarks ConcatAll with monoid // TestComposeVsChain demonstrates the key difference between Compose and Chain func TestComposeVsChain(t *testing.T) { - double := func(x int) int { return x * 2 } + double := N.Mul(2) increment := func(x int) int { return x + 1 } // Compose executes RIGHT-TO-LEFT @@ -499,7 +500,7 @@ func BenchmarkMonoidConcatAll(b *testing.B) { monoid := Monoid[int]() combined := M.ConcatAll(monoid)([]Endomorphism[int]{double, increment, square}) b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = combined(5) } } @@ -509,7 +510,7 @@ func BenchmarkChain(b *testing.B) { chainWithIncrement := Chain(increment) chained := chainWithIncrement(double) b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = chained(5) } } @@ -704,7 +705,7 @@ func TestApEqualsCompose(t *testing.T) { // TestChainFirst tests the ChainFirst operation func TestChainFirst(t *testing.T) { - double := func(x int) int { return x * 2 } + double := N.Mul(2) // Track side effect var sideEffect int diff --git a/v2/endomorphism/monoid.go b/v2/endomorphism/monoid.go index 4af3e38..1c33433 100644 --- a/v2/endomorphism/monoid.go +++ b/v2/endomorphism/monoid.go @@ -35,7 +35,7 @@ import ( // // Example: // -// myFunc := func(x int) int { return x * 2 } +// myFunc := N.Mul(2) // endo := endomorphism.Of(myFunc) func Of[F ~func(A) A, A any](f F) Endomorphism[A] { return f @@ -75,7 +75,7 @@ func Unwrap[F ~func(A) A, A any](f Endomorphism[A]) F { // result := id(42) // Returns: 42 // // // Identity is neutral for composition -// double := func(x int) int { return x * 2 } +// double := N.Mul(2) // composed := endomorphism.Compose(id, double) // // composed behaves exactly like double func Identity[A any]() Endomorphism[A] { @@ -103,7 +103,7 @@ func Identity[A any]() Endomorphism[A] { // import S "github.com/IBM/fp-go/v2/semigroup" // // sg := endomorphism.Semigroup[int]() -// double := func(x int) int { return x * 2 } +// double := N.Mul(2) // increment := func(x int) int { return x + 1 } // // // Combine using the semigroup (RIGHT-TO-LEFT execution) @@ -139,7 +139,7 @@ func Semigroup[A any]() S.Semigroup[Endomorphism[A]] { // import M "github.com/IBM/fp-go/v2/monoid" // // monoid := endomorphism.Monoid[int]() -// double := func(x int) int { return x * 2 } +// double := N.Mul(2) // increment := func(x int) int { return x + 1 } // square := func(x int) int { return x * x } // diff --git a/v2/endomorphism/types.go b/v2/endomorphism/types.go index a0f99c2..142df91 100644 --- a/v2/endomorphism/types.go +++ b/v2/endomorphism/types.go @@ -29,7 +29,7 @@ type ( // Example: // // // Simple endomorphisms on integers - // double := func(x int) int { return x * 2 } + // double := N.Mul(2) // increment := func(x int) int { return x + 1 } // // // Both are endomorphisms of type Endomorphism[int] diff --git a/v2/erasure/erasure_test.go b/v2/erasure/erasure_test.go index 6ebd151..63a75d2 100644 --- a/v2/erasure/erasure_test.go +++ b/v2/erasure/erasure_test.go @@ -23,6 +23,7 @@ import ( E "github.com/IBM/fp-go/v2/either" F "github.com/IBM/fp-go/v2/function" + N "github.com/IBM/fp-go/v2/number" "github.com/stretchr/testify/assert" ) @@ -266,7 +267,7 @@ func TestEither(t *testing.T) { erased := Erase(42) result := F.Pipe1( SafeUnerase[int](erased), - E.Map[error](func(x int) int { return x * 2 }), + E.Map[error](N.Mul(2)), ) assert.True(t, E.IsRight(result)) diff --git a/v2/io/coverage_test.go b/v2/io/coverage_test.go index 3da448b..6e5758f 100644 --- a/v2/io/coverage_test.go +++ b/v2/io/coverage_test.go @@ -23,6 +23,7 @@ import ( F "github.com/IBM/fp-go/v2/function" M "github.com/IBM/fp-go/v2/monoid" + N "github.com/IBM/fp-go/v2/number" S "github.com/IBM/fp-go/v2/semigroup" T "github.com/IBM/fp-go/v2/tuple" "github.com/stretchr/testify/assert" @@ -55,14 +56,14 @@ func TestMapTo(t *testing.T) { // Test MonadApSeq func TestMonadApSeq(t *testing.T) { - f := Of(func(x int) int { return x * 2 }) + f := Of(N.Mul(2)) result := MonadApSeq(f, Of(21)) assert.Equal(t, 42, result()) } // Test ApPar func TestApPar(t *testing.T) { - f := Of(func(x int) int { return x * 2 }) + f := Of(N.Mul(2)) result := F.Pipe1(f, ApPar[int](Of(21))) assert.Equal(t, 42, result()) } @@ -128,14 +129,14 @@ func TestDefer(t *testing.T) { // Test MonadFlap func TestMonadFlap(t *testing.T) { - f := Of(func(x int) int { return x * 2 }) + f := Of(N.Mul(2)) result := MonadFlap(f, 21) assert.Equal(t, 42, result()) } // Test Flap func TestFlap(t *testing.T) { - f := Of(func(x int) int { return x * 2 }) + f := Of(N.Mul(2)) result := F.Pipe1(f, Flap[int](21)) assert.Equal(t, 42, result()) } @@ -355,7 +356,7 @@ func TestApplicativeTypeClass(t *testing.T) { assert.Equal(t, 21, io1()) // Test Map - io2 := app.Map(func(x int) int { return x * 2 })(io1) + io2 := app.Map(N.Mul(2))(io1) assert.Equal(t, 42, io2()) } diff --git a/v2/iterator/iter/iter.go b/v2/iterator/iter/iter.go index a033ece..d14cfbf 100644 --- a/v2/iterator/iter/iter.go +++ b/v2/iterator/iter/iter.go @@ -33,7 +33,7 @@ // // // Create a sequence and transform it // seq := From(1, 2, 3, 4, 5) -// doubled := Map(func(x int) int { return x * 2 })(seq) +// doubled := Map(N.Mul(2))(seq) // // // Filter and reduce // evens := Filter(func(x int) bool { return x%2 == 0 })(doubled) @@ -83,7 +83,7 @@ func Of2[K, A any](k K, a A) Seq2[K, A] { // Example: // // seq := From(1, 2, 3) -// result := MonadMap(seq, func(x int) int { return x * 2 }) +// result := MonadMap(seq, N.Mul(2)) // // yields: 2, 4, 6 func MonadMap[A, B any](as Seq[A], f func(A) B) Seq[B] { return func(yield Predicate[B]) { @@ -100,7 +100,7 @@ func MonadMap[A, B any](as Seq[A], f func(A) B) Seq[B] { // // Example: // -// double := Map(func(x int) int { return x * 2 }) +// double := Map(N.Mul(2)) // seq := From(1, 2, 3) // result := double(seq) // // yields: 2, 4, 6 @@ -476,7 +476,7 @@ func Flatten[A any](mma Seq[Seq[A]]) Seq[A] { // // Example: // -// fns := From(func(x int) int { return x * 2 }, func(x int) int { return x + 10 }) +// fns := From(N.Mul(2), func(x int) int { return x + 10 }) // vals := From(5, 3) // result := MonadAp(fns, vals) // // yields: 10, 6, 15, 13 (each function applied to each value) @@ -492,7 +492,7 @@ func MonadAp[B, A any](fab Seq[func(A) B], fa Seq[A]) Seq[B] { // Example: // // applyTo5 := Ap(From(5)) -// fns := From(func(x int) int { return x * 2 }, func(x int) int { return x + 10 }) +// fns := From(N.Mul(2), func(x int) int { return x + 10 }) // result := applyTo5(fns) // // yields: 10, 15 // @@ -799,7 +799,7 @@ func FoldMapWithKey[K, A, B any](m M.Monoid[B]) func(func(K, A) B) func(Seq2[K, // // Example: // -// fns := From(func(x int) int { return x * 2 }, func(x int) int { return x + 10 }) +// fns := From(N.Mul(2), func(x int) int { return x + 10 }) // result := MonadFlap(fns, 5) // // yields: 10, 15 // diff --git a/v2/iterator/iter/iter_test.go b/v2/iterator/iter/iter_test.go index c2ac3f2..17cab88 100644 --- a/v2/iterator/iter/iter_test.go +++ b/v2/iterator/iter/iter_test.go @@ -23,6 +23,7 @@ import ( "testing" F "github.com/IBM/fp-go/v2/function" + N "github.com/IBM/fp-go/v2/number" O "github.com/IBM/fp-go/v2/option" S "github.com/IBM/fp-go/v2/string" "github.com/stretchr/testify/assert" @@ -64,14 +65,14 @@ func TestEmpty(t *testing.T) { func TestMonadMap(t *testing.T) { seq := From(1, 2, 3) - doubled := MonadMap(seq, func(x int) int { return x * 2 }) + doubled := MonadMap(seq, N.Mul(2)) result := toSlice(doubled) assert.Equal(t, []int{2, 4, 6}, result) } func TestMap(t *testing.T) { seq := From(1, 2, 3) - double := Map(func(x int) int { return x * 2 }) + double := Map(N.Mul(2)) result := toSlice(double(seq)) assert.Equal(t, []int{2, 4, 6}, result) } @@ -249,7 +250,7 @@ func TestFlatten(t *testing.T) { func TestMonadAp(t *testing.T) { fns := From( - func(x int) int { return x * 2 }, + N.Mul(2), func(x int) int { return x + 10 }, ) vals := From(1, 2) @@ -259,7 +260,7 @@ func TestMonadAp(t *testing.T) { func TestAp(t *testing.T) { fns := From( - func(x int) int { return x * 2 }, + N.Mul(2), func(x int) int { return x + 10 }, ) vals := From(1, 2) @@ -423,7 +424,7 @@ func TestFoldMapWithKey(t *testing.T) { func TestMonadFlap(t *testing.T) { fns := From( - func(x int) int { return x * 2 }, + N.Mul(2), func(x int) int { return x + 10 }, ) result := MonadFlap(fns, 5) @@ -432,7 +433,7 @@ func TestMonadFlap(t *testing.T) { func TestFlap(t *testing.T) { fns := From( - func(x int) int { return x * 2 }, + N.Mul(2), func(x int) int { return x + 10 }, ) flapper := Flap[int](5) diff --git a/v2/lazy/doc.go b/v2/lazy/doc.go index c322972..d0a70e1 100644 --- a/v2/lazy/doc.go +++ b/v2/lazy/doc.go @@ -58,7 +58,7 @@ // // Transform it // doubled := F.Pipe1( // computation, -// lazy.Map(func(x int) int { return x * 2 }), +// lazy.Map(N.Mul(2)), // ) // // // Evaluate when needed diff --git a/v2/lazy/lazy.go b/v2/lazy/lazy.go index b612e01..165abdb 100644 --- a/v2/lazy/lazy.go +++ b/v2/lazy/lazy.go @@ -71,7 +71,7 @@ func MonadOf[A any](a A) Lazy[A] { // Example: // // computation := lazy.Of(5) -// doubled := lazy.MonadMap(computation, func(x int) int { return x * 2 }) +// doubled := lazy.MonadMap(computation, N.Mul(2)) // result := doubled() // 10 func MonadMap[A, B any](fa Lazy[A], f func(A) B) Lazy[B] { return io.MonadMap(fa, f) @@ -84,7 +84,7 @@ func MonadMap[A, B any](fa Lazy[A], f func(A) B) Lazy[B] { // // Example: // -// double := lazy.Map(func(x int) int { return x * 2 }) +// double := lazy.Map(N.Mul(2)) // computation := lazy.Of(5) // result := double(computation)() // 10 // @@ -141,7 +141,7 @@ func Chain[A, B any](f Kleisli[A, B]) Kleisli[Lazy[A], B] { // // Example: // -// lazyFunc := lazy.Of(func(x int) int { return x * 2 }) +// lazyFunc := lazy.Of(N.Mul(2)) // lazyValue := lazy.Of(5) // result := lazy.MonadAp(lazyFunc, lazyValue)() // 10 func MonadAp[B, A any](mab Lazy[func(A) B], ma Lazy[A]) Lazy[B] { @@ -157,7 +157,7 @@ func MonadAp[B, A any](mab Lazy[func(A) B], ma Lazy[A]) Lazy[B] { // // lazyValue := lazy.Of(5) // applyTo5 := lazy.Ap[int](lazyValue) -// lazyFunc := lazy.Of(func(x int) int { return x * 2 }) +// lazyFunc := lazy.Of(N.Mul(2)) // result := applyTo5(lazyFunc)() // 10 func Ap[B, A any](ma Lazy[A]) func(Lazy[func(A) B]) Lazy[B] { return io.ApSeq[B](ma) diff --git a/v2/lazy/lazy_extended_test.go b/v2/lazy/lazy_extended_test.go index 08a55c4..85de8b7 100644 --- a/v2/lazy/lazy_extended_test.go +++ b/v2/lazy/lazy_extended_test.go @@ -23,6 +23,7 @@ import ( F "github.com/IBM/fp-go/v2/function" "github.com/IBM/fp-go/v2/internal/utils" M "github.com/IBM/fp-go/v2/monoid" + N "github.com/IBM/fp-go/v2/number" L "github.com/IBM/fp-go/v2/optics/lens" "github.com/stretchr/testify/assert" ) @@ -54,7 +55,7 @@ func TestMonadOf(t *testing.T) { } func TestMonadMap(t *testing.T) { - result := MonadMap(Of(5), func(x int) int { return x * 2 }) + result := MonadMap(Of(5), N.Mul(2)) assert.Equal(t, 10, result()) } @@ -103,7 +104,7 @@ func TestChainTo(t *testing.T) { } func TestMonadAp(t *testing.T) { - lazyFunc := Of(func(x int) int { return x * 2 }) + lazyFunc := Of(N.Mul(2)) lazyValue := Of(5) result := MonadAp(lazyFunc, lazyValue) assert.Equal(t, 10, result()) @@ -494,7 +495,7 @@ func TestMapComposition(t *testing.T) { // Test mapping multiple transformations result := F.Pipe3( Of(5), - Map(func(x int) int { return x * 2 }), + Map(N.Mul(2)), Map(func(x int) int { return x + 10 }), Map(func(x int) int { return x }), ) diff --git a/v2/lazy/types.go b/v2/lazy/types.go index 9ecf8dc..e8075a6 100644 --- a/v2/lazy/types.go +++ b/v2/lazy/types.go @@ -17,7 +17,7 @@ type ( // computation := lazy.Of(42) // // // Transform it (not evaluated yet) - // doubled := lazy.Map(func(x int) int { return x * 2 })(computation) + // doubled := lazy.Map(N.Mul(2))(computation) // // // Evaluate when needed // result := doubled() // 84 @@ -52,7 +52,7 @@ type ( // Example: // // // An operator that doubles the value in a lazy computation - // doubleOp := lazy.Map(func(x int) int { return x * 2 }) + // doubleOp := lazy.Map(N.Mul(2)) // // // Apply it to a lazy computation // result := doubleOp(lazy.Of(5))() // 10 diff --git a/v2/logging/logger_test.go b/v2/logging/logger_test.go index 34687b2..49e18fe 100644 --- a/v2/logging/logger_test.go +++ b/v2/logging/logger_test.go @@ -247,7 +247,7 @@ func TestLoggingCallbacks_ConsecutiveCalls(t *testing.T) { // BenchmarkLoggingCallbacks_NoLoggers benchmarks the no-logger case. func BenchmarkLoggingCallbacks_NoLoggers(b *testing.B) { - for i := 0; i < b.N; i++ { + for b.Loop() { LoggingCallbacks() } } @@ -258,7 +258,7 @@ func BenchmarkLoggingCallbacks_OneLogger(b *testing.B) { logger := log.New(&buf, "", 0) b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { LoggingCallbacks(logger) } } @@ -270,7 +270,7 @@ func BenchmarkLoggingCallbacks_TwoLoggers(b *testing.B) { logger2 := log.New(&buf2, "", 0) b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { LoggingCallbacks(logger1, logger2) } } diff --git a/v2/monoid/monoid_test.go b/v2/monoid/monoid_test.go index bf98a28..e38bc5e 100644 --- a/v2/monoid/monoid_test.go +++ b/v2/monoid/monoid_test.go @@ -690,7 +690,7 @@ func BenchmarkConcatAll(b *testing.B) { } b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = concatAll(numbers) } } @@ -710,7 +710,7 @@ func BenchmarkFunctionMonoid(b *testing.B) { combined := funcMonoid.Concat(f1, f2) b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { _ = combined("benchmark") } } diff --git a/v2/optics/iso/isos_test.go b/v2/optics/iso/isos_test.go index e356451..c3593b0 100644 --- a/v2/optics/iso/isos_test.go +++ b/v2/optics/iso/isos_test.go @@ -19,6 +19,7 @@ import ( "testing" "time" + A "github.com/IBM/fp-go/v2/array" "github.com/stretchr/testify/assert" ) @@ -93,31 +94,31 @@ func TestLines(t *testing.T) { iso := Lines() t.Run("Get joins lines with newline", func(t *testing.T) { - lines := []string{"line1", "line2", "line3"} + lines := A.From("line1", "line2", "line3") result := iso.Get(lines) assert.Equal(t, "line1\nline2\nline3", result) }) t.Run("Get handles single line", func(t *testing.T) { - lines := []string{"single line"} + lines := A.Of("single line") result := iso.Get(lines) assert.Equal(t, "single line", result) }) t.Run("Get handles empty slice", func(t *testing.T) { - lines := []string{} + lines := A.Empty[string]() result := iso.Get(lines) assert.Equal(t, "", result) }) t.Run("Get handles empty strings in slice", func(t *testing.T) { - lines := []string{"a", "", "b"} + lines := A.From("a", "", "b") result := iso.Get(lines) assert.Equal(t, "a\n\nb", result) }) t.Run("Get handles slice with only empty strings", func(t *testing.T) { - lines := []string{"", "", ""} + lines := A.From("", "", "") result := iso.Get(lines) assert.Equal(t, "\n\n", result) }) @@ -340,20 +341,20 @@ func TestLinesRoundTripLaws(t *testing.T) { t.Run("Law 1: Empty slice special case", func(t *testing.T) { // Empty slice becomes "" which splits to [""] // This is expected behavior of strings.Split - original := []string{} + original := A.Empty[string]() text := iso.Get(original) // "" result := iso.ReverseGet(text) // [""] assert.Equal(t, []string{""}, result) }) t.Run("Law 2: Get(ReverseGet(str)) == str", func(t *testing.T) { - testCases := []string{ + testCases := A.From( "line1\nline2", "single", "", "a\n\nb", "\n\n", - } + ) for _, original := range testCases { result := iso.Get(iso.ReverseGet(original)) @@ -367,13 +368,13 @@ func TestUnixMilliRoundTripLaws(t *testing.T) { iso := UnixMilli() t.Run("Law 1: ReverseGet(Get(millis)) == millis", func(t *testing.T) { - testCases := []int64{ + testCases := A.From( 0, 1609459200000, -86400000, 1234567890000, time.Now().UnixMilli(), - } + ) for _, original := range testCases { result := iso.ReverseGet(iso.Get(original)) @@ -382,12 +383,12 @@ func TestUnixMilliRoundTripLaws(t *testing.T) { }) t.Run("Law 2: Get(ReverseGet(time)) == time (with millisecond precision)", func(t *testing.T) { - testCases := []time.Time{ + testCases := A.From( time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), time.Unix(0, 0).UTC(), time.Date(1969, 12, 31, 0, 0, 0, 0, time.UTC), time.Now().Truncate(time.Millisecond), - } + ) for _, original := range testCases { result := iso.Get(iso.ReverseGet(original)) @@ -410,7 +411,7 @@ func TestIsosComposition(t *testing.T) { assert.Equal(t, []string{"line1", "line2", "line3"}, lines) // Reverse: lines to string to bytes - originalLines := []string{"a", "b", "c"} + originalLines := A.From("a", "b", "c") text := linesIso.Get(originalLines) resultBytes := utf8Iso.ReverseGet(text) assert.Equal(t, []byte("a\nb\nc"), resultBytes) diff --git a/v2/optics/iso/option/isos_test.go b/v2/optics/iso/option/isos_test.go index 1b60b97..0ec3bd2 100644 --- a/v2/optics/iso/option/isos_test.go +++ b/v2/optics/iso/option/isos_test.go @@ -19,6 +19,7 @@ import ( "testing" F "github.com/IBM/fp-go/v2/function" + N "github.com/IBM/fp-go/v2/number" "github.com/IBM/fp-go/v2/optics/iso" O "github.com/IBM/fp-go/v2/option" "github.com/stretchr/testify/assert" @@ -211,7 +212,7 @@ func TestFromZeroWithModify(t *testing.T) { t.Run("Modify applies transformation to non-zero value", func(t *testing.T) { double := func(opt O.Option[int]) O.Option[int] { - return O.MonadMap(opt, func(x int) int { return x * 2 }) + return O.MonadMap(opt, N.Mul(2)) } result := iso.Modify[int](double)(isoInt)(5) @@ -220,7 +221,7 @@ func TestFromZeroWithModify(t *testing.T) { t.Run("Modify preserves zero value", func(t *testing.T) { double := func(opt O.Option[int]) O.Option[int] { - return O.MonadMap(opt, func(x int) int { return x * 2 }) + return O.MonadMap(opt, N.Mul(2)) } result := iso.Modify[int](double)(isoInt)(0) @@ -235,7 +236,7 @@ func TestFromZeroWithCompose(t *testing.T) { // Create an isomorphism that doubles/halves values doubleIso := iso.MakeIso( func(opt O.Option[int]) O.Option[int] { - return O.MonadMap(opt, func(x int) int { return x * 2 }) + return O.MonadMap(opt, N.Mul(2)) }, func(opt O.Option[int]) O.Option[int] { return O.MonadMap(opt, func(x int) int { return x / 2 }) diff --git a/v2/optics/lens/lens_laws_test.go b/v2/optics/lens/lens_laws_test.go index 13759e7..4ba26a3 100644 --- a/v2/optics/lens/lens_laws_test.go +++ b/v2/optics/lens/lens_laws_test.go @@ -20,6 +20,7 @@ import ( EQ "github.com/IBM/fp-go/v2/eq" F "github.com/IBM/fp-go/v2/function" + N "github.com/IBM/fp-go/v2/number" "github.com/stretchr/testify/assert" ) @@ -555,7 +556,7 @@ func TestModifyLaws(t *testing.T) { // Modify composition: Modify(f ∘ g) = Modify(f) ∘ Modify(g) t.Run("ModifyComposition", func(t *testing.T) { - f := func(x int) int { return x * 2 } + f := N.Mul(2) g := func(x int) int { return x + 3 } // Modify(f ∘ g) diff --git a/v2/optics/lens/option/from_test.go b/v2/optics/lens/option/from_test.go index 11e0280..1d3556b 100644 --- a/v2/optics/lens/option/from_test.go +++ b/v2/optics/lens/option/from_test.go @@ -20,6 +20,7 @@ import ( EQT "github.com/IBM/fp-go/v2/eq/testing" F "github.com/IBM/fp-go/v2/function" + N "github.com/IBM/fp-go/v2/number" ISO "github.com/IBM/fp-go/v2/optics/iso" L "github.com/IBM/fp-go/v2/optics/lens" LT "github.com/IBM/fp-go/v2/optics/lens/testing" @@ -281,7 +282,7 @@ func TestFromIsoModify(t *testing.T) { t.Run("ModifySomeValue", func(t *testing.T) { config := Config{timeout: 30, retries: 3} // Double the timeout value - modified := L.Modify[Config](O.Map(func(x int) int { return x * 2 }))(optTimeoutLens)(config) + modified := L.Modify[Config](O.Map(N.Mul(2)))(optTimeoutLens)(config) assert.Equal(t, 60, modified.timeout) }) diff --git a/v2/option/logger.go b/v2/option/logger.go index 1dd534c..db99aa2 100644 --- a/v2/option/logger.go +++ b/v2/option/logger.go @@ -48,7 +48,7 @@ func _log[A any](left func(string, ...any), right func(string, ...any), prefix s // result := F.Pipe2( // Some(42), // logger("step1"), // logs "step1: 42" -// Map(func(x int) int { return x * 2 }), +// Map(N.Mul(2)), // ) // Some(84) // // result := F.Pipe1( diff --git a/v2/option/option.go b/v2/option/option.go index a019116..2152283 100644 --- a/v2/option/option.go +++ b/v2/option/option.go @@ -93,7 +93,7 @@ func FromValidation[A, B any](f func(A) (B, bool)) Kleisli[A, B] { // // Example: // -// fab := Some(func(x int) int { return x * 2 }) +// fab := Some(N.Mul(2)) // fa := Some(5) // result := MonadAp(fab, fa) // Some(10) func MonadAp[B, A any](fab Option[func(A) B], fa Option[A]) Option[B] { @@ -109,7 +109,7 @@ func MonadAp[B, A any](fab Option[func(A) B], fa Option[A]) Option[B] { // // fa := Some(5) // applyTo5 := Ap[int](fa) -// fab := Some(func(x int) int { return x * 2 }) +// fab := Some(N.Mul(2)) // result := applyTo5(fab) // Some(10) func Ap[B, A any](fa Option[A]) Operator[func(A) B, B] { return F.Bind2nd(MonadAp[B, A], fa) @@ -121,7 +121,7 @@ func Ap[B, A any](fa Option[A]) Operator[func(A) B, B] { // Example: // // fa := Some(5) -// result := MonadMap(fa, func(x int) int { return x * 2 }) // Some(10) +// result := MonadMap(fa, N.Mul(2)) // Some(10) func MonadMap[A, B any](fa Option[A], f func(A) B) Option[B] { return MonadChain(fa, F.Flow2(f, Some[B])) } @@ -131,7 +131,7 @@ func MonadMap[A, B any](fa Option[A], f func(A) B) Option[B] { // // Example: // -// double := Map(func(x int) int { return x * 2 }) +// double := Map(N.Mul(2)) // result := double(Some(5)) // Some(10) // result := double(None[int]()) // None func Map[A, B any](f func(a A) B) Operator[A, B] { @@ -387,7 +387,7 @@ func Filter[A any](pred func(A) bool) Kleisli[Option[A], A] { // // Example: // -// fab := Some(func(x int) int { return x * 2 }) +// fab := Some(N.Mul(2)) // result := MonadFlap(fab, 5) // Some(10) func MonadFlap[B, A any](fab Option[func(A) B], a A) Option[B] { return FC.MonadFlap(MonadMap[func(A) B, B], fab, a) @@ -398,7 +398,7 @@ func MonadFlap[B, A any](fab Option[func(A) B], a A) Option[B] { // Example: // // applyFive := Flap[int](5) -// fab := Some(func(x int) int { return x * 2 }) +// fab := Some(N.Mul(2)) // result := applyFive(fab) // Some(10) func Flap[B, A any](a A) Operator[func(A) B, B] { return FC.Flap(Map[func(A) B, B], a) diff --git a/v2/option/option_extended_test.go b/v2/option/option_extended_test.go index dd8e6e7..8fad460 100644 --- a/v2/option/option_extended_test.go +++ b/v2/option/option_extended_test.go @@ -22,6 +22,7 @@ import ( F "github.com/IBM/fp-go/v2/function" M "github.com/IBM/fp-go/v2/monoid" + N "github.com/IBM/fp-go/v2/number" P "github.com/IBM/fp-go/v2/pair" S "github.com/IBM/fp-go/v2/semigroup" T "github.com/IBM/fp-go/v2/tuple" @@ -58,7 +59,7 @@ func TestFromValidation(t *testing.T) { // Test MonadAp func TestMonadAp(t *testing.T) { - double := func(x int) int { return x * 2 } + double := N.Mul(2) assert.Equal(t, Some(10), MonadAp(Some(double), Some(5))) assert.Equal(t, None[int](), MonadAp(Some(double), None[int]())) @@ -68,7 +69,7 @@ func TestMonadAp(t *testing.T) { // Test MonadMap func TestMonadMap(t *testing.T) { - double := func(x int) int { return x * 2 } + double := N.Mul(2) assert.Equal(t, Some(10), MonadMap(Some(5), double)) assert.Equal(t, None[int](), MonadMap(None[int](), double)) @@ -190,7 +191,7 @@ func TestFilter(t *testing.T) { // Test MonadFlap func TestMonadFlap(t *testing.T) { - double := func(x int) int { return x * 2 } + double := N.Mul(2) assert.Equal(t, Some(10), MonadFlap(Some(double), 5)) assert.Equal(t, None[int](), MonadFlap(None[func(int) int](), 5)) @@ -199,7 +200,7 @@ func TestMonadFlap(t *testing.T) { // Test Flap func TestFlap(t *testing.T) { applyFive := Flap[int](5) - double := func(x int) int { return x * 2 } + double := N.Mul(2) assert.Equal(t, Some(10), applyFive(Some(double))) assert.Equal(t, None[int](), applyFive(None[func(int) int]())) diff --git a/v2/pair/pair_test.go b/v2/pair/pair_test.go index ca72534..3ddb300 100644 --- a/v2/pair/pair_test.go +++ b/v2/pair/pair_test.go @@ -17,12 +17,12 @@ package pair import ( "fmt" + "strconv" "testing" EQ "github.com/IBM/fp-go/v2/eq" - M "github.com/IBM/fp-go/v2/monoid" N "github.com/IBM/fp-go/v2/number" - SG "github.com/IBM/fp-go/v2/semigroup" + S "github.com/IBM/fp-go/v2/string" "github.com/IBM/fp-go/v2/tuple" "github.com/stretchr/testify/assert" ) @@ -67,9 +67,7 @@ func TestFirstAndSecond(t *testing.T) { func TestMonadMapHead(t *testing.T) { p := MakePair(5, "hello") - p2 := MonadMapHead(p, func(n int) string { - return fmt.Sprintf("%d", n) - }) + p2 := MonadMapHead(p, strconv.Itoa) assert.Equal(t, "5", Head(p2)) assert.Equal(t, "hello", Tail(p2)) } @@ -85,9 +83,7 @@ func TestMonadMapTail(t *testing.T) { func TestMonadMap(t *testing.T) { p := MakePair(10, "test") - p2 := MonadMap(p, func(n int) string { - return fmt.Sprintf("value: %d", n) - }) + p2 := MonadMap(p, S.Format[int]("value: %d")) assert.Equal(t, "value: 10", Head(p2)) assert.Equal(t, "test", Tail(p2)) } @@ -95,17 +91,15 @@ func TestMonadMap(t *testing.T) { func TestMonadBiMap(t *testing.T) { p := MakePair(5, "hello") p2 := MonadBiMap(p, - func(n int) string { return fmt.Sprintf("%d", n) }, - func(s string) int { return len(s) }, + strconv.Itoa, + S.Size, ) assert.Equal(t, "5", Head(p2)) assert.Equal(t, 5, Tail(p2)) } func TestMapHead(t *testing.T) { - mapper := MapHead[string](func(n int) string { - return fmt.Sprintf("%d", n) - }) + mapper := MapHead[string](strconv.Itoa) p := MakePair(42, "world") p2 := mapper(p) assert.Equal(t, "42", Head(p2)) @@ -134,8 +128,8 @@ func TestMap(t *testing.T) { func TestBiMap(t *testing.T) { mapper := BiMap( - func(n int) string { return fmt.Sprintf("n=%d", n) }, - func(s string) int { return len(s) }, + S.Format[int]("n=%d"), + S.Size, ) p := MakePair(7, "hello") p2 := mapper(p) @@ -151,7 +145,7 @@ func TestSwap(t *testing.T) { } func TestMonadChainHead(t *testing.T) { - strConcat := SG.MakeSemigroup(func(a, b string) string { return a + b }) + strConcat := S.Semigroup p := MakePair(5, "hello") p2 := MonadChainHead(strConcat, p, func(n int) Pair[string, string] { return MakePair(fmt.Sprintf("%d", n), "!") @@ -181,7 +175,7 @@ func TestMonadChain(t *testing.T) { } func TestChainHead(t *testing.T) { - strConcat := SG.MakeSemigroup(func(a, b string) string { return a + b }) + strConcat := S.Semigroup chain := ChainHead(strConcat, func(n int) Pair[string, string] { return MakePair(fmt.Sprintf("%d", n), "!") }) @@ -214,8 +208,8 @@ func TestChain(t *testing.T) { } func TestMonadApHead(t *testing.T) { - strConcat := SG.MakeSemigroup(func(a, b string) string { return a + b }) - pf := MakePair(func(n int) string { return fmt.Sprintf("%d", n) }, "!") + strConcat := S.Semigroup + pf := MakePair(strconv.Itoa, "!") pv := MakePair(42, "hello") result := MonadApHead(strConcat, pf, pv) assert.Equal(t, "42", Head(result)) @@ -224,7 +218,7 @@ func TestMonadApHead(t *testing.T) { func TestMonadApTail(t *testing.T) { intSum := N.SemigroupSum[int]() - pf := MakePair(10, func(s string) int { return len(s) }) + pf := MakePair(10, S.Size) pv := MakePair(5, "hello") result := MonadApTail(intSum, pf, pv) assert.Equal(t, 15, Head(result)) // 5 + 10 @@ -241,7 +235,7 @@ func TestMonadAp(t *testing.T) { } func TestApHead(t *testing.T) { - strConcat := SG.MakeSemigroup(func(a, b string) string { return a + b }) + strConcat := S.Semigroup pv := MakePair(100, "world") ap := ApHead[string, int, string](strConcat, pv) pf := MakePair(func(n int) string { return fmt.Sprintf("num=%d", n) }, "!") @@ -254,7 +248,7 @@ func TestApTail(t *testing.T) { intSum := N.SemigroupSum[int]() pv := MakePair(20, "hello") ap := ApTail[int, string, int](intSum, pv) - pf := MakePair(5, func(s string) int { return len(s) }) + pf := MakePair(5, S.Size) result := ap(pf) assert.Equal(t, 25, Head(result)) // 20 + 5 assert.Equal(t, 5, Tail(result)) @@ -287,9 +281,7 @@ func TestUnpaired(t *testing.T) { } func TestMerge(t *testing.T) { - add := func(b int) func(a int) int { - return func(a int) int { return a + b } - } + add := N.Add[int] merge := Merge(add) result := merge(MakePair(3, 4)) assert.Equal(t, 7, result) @@ -337,10 +329,7 @@ func TestFormat(t *testing.T) { } func TestMonadHead(t *testing.T) { - stringMonoid := M.MakeMonoid( - func(a, b string) string { return a + b }, - "", - ) + stringMonoid := S.Monoid monad := MonadHead[int, string, string](stringMonoid) // Test Of @@ -349,7 +338,7 @@ func TestMonadHead(t *testing.T) { assert.Equal(t, "", Tail(p)) // Test Map - mapper := monad.Map(func(n int) string { return fmt.Sprintf("%d", n) }) + mapper := monad.Map(strconv.Itoa) p2 := mapper(MakePair(100, "!")) assert.Equal(t, "100", Head(p2)) assert.Equal(t, "!", Tail(p2)) @@ -372,10 +361,7 @@ func TestMonadHead(t *testing.T) { } func TestPointedHead(t *testing.T) { - stringMonoid := M.MakeMonoid( - func(a, b string) string { return a + b }, - "", - ) + stringMonoid := S.Monoid pointed := PointedHead[int](stringMonoid) p := pointed.Of(42) assert.Equal(t, 42, Head(p)) @@ -392,10 +378,7 @@ func TestFunctorHead(t *testing.T) { } func TestApplicativeHead(t *testing.T) { - stringMonoid := M.MakeMonoid( - func(a, b string) string { return a + b }, - "", - ) + stringMonoid := S.Monoid applicative := ApplicativeHead[int, string, string](stringMonoid) // Test Of @@ -404,7 +387,7 @@ func TestApplicativeHead(t *testing.T) { assert.Equal(t, "", Tail(p)) // Test Map - mapper := applicative.Map(func(n int) string { return fmt.Sprintf("%d", n) }) + mapper := applicative.Map(strconv.Itoa) p2 := mapper(MakePair(42, "!")) assert.Equal(t, "42", Head(p2)) assert.Equal(t, "!", Tail(p2)) @@ -428,7 +411,7 @@ func TestMonadTail(t *testing.T) { assert.Equal(t, "hello", Tail(p)) // Test Map - mapper := monad.Map(func(s string) int { return len(s) }) + mapper := monad.Map(S.Size) p2 := mapper(MakePair(5, "world")) assert.Equal(t, 5, Head(p2)) assert.Equal(t, 5, Tail(p2)) @@ -444,7 +427,7 @@ func TestMonadTail(t *testing.T) { // Test Ap pv := MakePair(5, "hello") ap := monad.Ap(pv) - pf := MakePair(10, func(s string) int { return len(s) }) + pf := MakePair(10, S.Size) p4 := ap(pf) assert.Equal(t, 15, Head(p4)) // 5 + 10 assert.Equal(t, 5, Tail(p4)) @@ -477,7 +460,7 @@ func TestApplicativeTail(t *testing.T) { assert.Equal(t, "world", Tail(p)) // Test Map - mapper := applicative.Map(func(s string) int { return len(s) }) + mapper := applicative.Map(S.Size) p2 := mapper(MakePair(5, "test")) assert.Equal(t, 5, Head(p2)) assert.Equal(t, 4, Tail(p2)) @@ -511,7 +494,7 @@ func TestPointed(t *testing.T) { func TestFunctor(t *testing.T) { functor := Functor[string, int, int]() - mapper := functor.Map(func(s string) int { return len(s) }) + mapper := functor.Map(S.Size) p := MakePair(7, "world") p2 := mapper(p) assert.Equal(t, 7, Head(p2)) diff --git a/v2/reader/reader.go b/v2/reader/reader.go index d132580..abaace0 100644 --- a/v2/reader/reader.go +++ b/v2/reader/reader.go @@ -212,7 +212,7 @@ func Compose[C, R, B any](ab Reader[R, B]) func(Reader[B, C]) Reader[R, C] { // // Example: // -// double := func(x int) int { return x * 2 } +// double := N.Mul(2) // r := reader.First[int, int, string](double) // result := r(tuple.MakeTuple2(5, "hello")) // (10, "hello") func First[A, B, C any](pab Reader[A, B]) Reader[T.Tuple2[A, C], T.Tuple2[B, C]] { @@ -226,7 +226,7 @@ func First[A, B, C any](pab Reader[A, B]) Reader[T.Tuple2[A, C], T.Tuple2[B, C]] // // Example: // -// double := func(x int) int { return x * 2 } +// double := N.Mul(2) // r := reader.Second[string, int, int](double) // result := r(tuple.MakeTuple2("hello", 5)) // ("hello", 10) func Second[A, B, C any](pbc Reader[B, C]) Reader[T.Tuple2[A, B], T.Tuple2[A, C]] { diff --git a/v2/reader/reader_test.go b/v2/reader/reader_test.go index 3b05d61..c947c61 100644 --- a/v2/reader/reader_test.go +++ b/v2/reader/reader_test.go @@ -21,6 +21,7 @@ import ( "testing" F "github.com/IBM/fp-go/v2/function" + N "github.com/IBM/fp-go/v2/number" T "github.com/IBM/fp-go/v2/tuple" "github.com/stretchr/testify/assert" @@ -134,14 +135,14 @@ func TestCompose(t *testing.T) { } func TestFirst(t *testing.T) { - double := func(x int) int { return x * 2 } + double := N.Mul(2) r := First[int, int, string](double) result := r(T.MakeTuple2(5, "hello")) assert.Equal(t, T.MakeTuple2(10, "hello"), result) } func TestSecond(t *testing.T) { - double := func(x int) int { return x * 2 } + double := N.Mul(2) r := Second[string](double) result := r(T.MakeTuple2("hello", 5)) assert.Equal(t, T.MakeTuple2("hello", 10), result) diff --git a/v2/readerioeither/readerioeither_test.go b/v2/readerioeither/readerioeither_test.go index 612065b..d482014 100644 --- a/v2/readerioeither/readerioeither_test.go +++ b/v2/readerioeither/readerioeither_test.go @@ -26,6 +26,7 @@ import ( F "github.com/IBM/fp-go/v2/function" "github.com/IBM/fp-go/v2/io" IOE "github.com/IBM/fp-go/v2/ioeither" + N "github.com/IBM/fp-go/v2/number" O "github.com/IBM/fp-go/v2/option" R "github.com/IBM/fp-go/v2/reader" RE "github.com/IBM/fp-go/v2/readereither" @@ -39,7 +40,7 @@ type testContext struct { func TestMonadMap(t *testing.T) { ctx := testContext{value: 10} - result := MonadMap(Of[testContext, error](5), func(x int) int { return x * 2 }) + result := MonadMap(Of[testContext, error](5), N.Mul(2)) assert.Equal(t, E.Right[error](10), result(ctx)()) } @@ -215,7 +216,7 @@ func TestChainOptionK(t *testing.T) { func TestMonadApSeq(t *testing.T) { ctx := testContext{value: 10} - fab := Of[testContext, error](func(x int) int { return x * 2 }) + fab := Of[testContext, error](N.Mul(2)) fa := Of[testContext, error](5) result := MonadApSeq(fab, fa) assert.Equal(t, E.Right[error](10), result(ctx)()) @@ -223,7 +224,7 @@ func TestMonadApSeq(t *testing.T) { func TestMonadApPar(t *testing.T) { ctx := testContext{value: 10} - fab := Of[testContext, error](func(x int) int { return x * 2 }) + fab := Of[testContext, error](N.Mul(2)) fa := Of[testContext, error](5) result := MonadApPar(fab, fa) assert.Equal(t, E.Right[error](10), result(ctx)()) @@ -550,7 +551,7 @@ func TestMemoize(t *testing.T) { func TestMonadFlap(t *testing.T) { ctx := testContext{value: 10} - fab := Of[testContext, error](func(x int) int { return x * 2 }) + fab := Of[testContext, error](N.Mul(2)) result := MonadFlap(fab, 5) assert.Equal(t, E.Right[error](10), result(ctx)()) } @@ -558,7 +559,7 @@ func TestMonadFlap(t *testing.T) { func TestFlap(t *testing.T) { ctx := testContext{value: 10} result := F.Pipe1( - Of[testContext, error](func(x int) int { return x * 2 }), + Of[testContext, error](N.Mul(2)), Flap[testContext, error, int](5), ) assert.Equal(t, E.Right[error](10), result(ctx)()) diff --git a/v2/readerioeither/types.go b/v2/readerioeither/types.go index 00d999e..8f124ec 100644 --- a/v2/readerioeither/types.go +++ b/v2/readerioeither/types.go @@ -84,7 +84,7 @@ type ( // - B: The output value type // // Example: - // var doubleOp Operator[Config, error, int, int] = Map(func(x int) int { return x * 2 }) + // var doubleOp Operator[Config, error, int, int] = Map(N.Mul(2)) Operator[R, E, A, B any] = Kleisli[R, E, ReaderIOEither[R, E, A], B] ReaderOption[R, A any] = readeroption.ReaderOption[R, A] diff --git a/v2/readerioresult/readerioeither_test.go b/v2/readerioresult/readerioeither_test.go index 8c33254..b97008d 100644 --- a/v2/readerioresult/readerioeither_test.go +++ b/v2/readerioresult/readerioeither_test.go @@ -25,6 +25,7 @@ import ( E "github.com/IBM/fp-go/v2/either" F "github.com/IBM/fp-go/v2/function" "github.com/IBM/fp-go/v2/ioresult" + N "github.com/IBM/fp-go/v2/number" O "github.com/IBM/fp-go/v2/option" R "github.com/IBM/fp-go/v2/reader" RE "github.com/IBM/fp-go/v2/readereither" @@ -39,7 +40,7 @@ type testContext struct { func TestMonadMap(t *testing.T) { ctx := testContext{value: 10} - res := MonadMap(Of[testContext](5), func(x int) int { return x * 2 }) + res := MonadMap(Of[testContext](5), N.Mul(2)) assert.Equal(t, result.Of(10), res(ctx)()) } @@ -215,7 +216,7 @@ func TestChainOptionK(t *testing.T) { func TestMonadApSeq(t *testing.T) { ctx := testContext{value: 10} - fab := Of[testContext](func(x int) int { return x * 2 }) + fab := Of[testContext](N.Mul(2)) fa := Of[testContext](5) res := MonadApSeq(fab, fa) assert.Equal(t, result.Of(10), res(ctx)()) @@ -223,7 +224,7 @@ func TestMonadApSeq(t *testing.T) { func TestMonadApPar(t *testing.T) { ctx := testContext{value: 10} - fab := Of[testContext](func(x int) int { return x * 2 }) + fab := Of[testContext](N.Mul(2)) fa := Of[testContext](5) res := MonadApPar(fab, fa) assert.Equal(t, result.Of(10), res(ctx)()) @@ -512,7 +513,7 @@ func TestMemoize(t *testing.T) { func TestMonadFlap(t *testing.T) { ctx := testContext{value: 10} - fab := Of[testContext](func(x int) int { return x * 2 }) + fab := Of[testContext](N.Mul(2)) res := MonadFlap(fab, 5) assert.Equal(t, result.Of(10), res(ctx)()) } @@ -520,7 +521,7 @@ func TestMonadFlap(t *testing.T) { func TestFlap(t *testing.T) { ctx := testContext{value: 10} res := F.Pipe1( - Of[testContext](func(x int) int { return x * 2 }), + Of[testContext](N.Mul(2)), Flap[testContext, int](5), ) assert.Equal(t, result.Of(10), res(ctx)()) diff --git a/v2/readerioresult/types.go b/v2/readerioresult/types.go index abbff9a..5f8e9da 100644 --- a/v2/readerioresult/types.go +++ b/v2/readerioresult/types.go @@ -98,6 +98,6 @@ type ( // - B: The output value type // // Example: - // var doubleOp Operator[Config, error, int, int] = Map(func(x int) int { return x * 2 }) + // var doubleOp Operator[Config, error, int, int] = Map(N.Mul(2)) Operator[R, A, B any] = Kleisli[R, ReaderIOResult[R, A], B] ) diff --git a/v2/readeroption/reader.go b/v2/readeroption/reader.go index 0bca54a..2e580b1 100644 --- a/v2/readeroption/reader.go +++ b/v2/readeroption/reader.go @@ -64,7 +64,7 @@ func SomeReader[E, A any](r Reader[E, A]) ReaderOption[E, A] { // Example: // // ro := readeroption.Of[Config](42) -// doubled := readeroption.MonadMap(ro, func(x int) int { return x * 2 }) +// doubled := readeroption.MonadMap(ro, N.Mul(2)) // //go:inline func MonadMap[E, A, B any](fa ReaderOption[E, A], f func(A) B) ReaderOption[E, B] { @@ -78,7 +78,7 @@ func MonadMap[E, A, B any](fa ReaderOption[E, A], f func(A) B) ReaderOption[E, B // // doubled := F.Pipe1( // readeroption.Of[Config](42), -// readeroption.Map[Config](func(x int) int { return x * 2 }), +// readeroption.Map[Config](N.Mul(2)), // ) // //go:inline diff --git a/v2/record/monoid_test.go b/v2/record/monoid_test.go index 4c888e5..3cfb467 100644 --- a/v2/record/monoid_test.go +++ b/v2/record/monoid_test.go @@ -23,7 +23,7 @@ import ( ) func TestUnionMonoid(t *testing.T) { - m := UnionMonoid[string](S.Semigroup()) + m := UnionMonoid[string](S.Semigroup) e := Empty[string, string]() diff --git a/v2/result/either.go b/v2/result/either.go index 31f4d87..c9fde0c 100644 --- a/v2/result/either.go +++ b/v2/result/either.go @@ -56,7 +56,7 @@ func FromIO[IO ~func() A, A any](f IO) Result[A] { // // Example: // -// fab := either.Right[error](func(x int) int { return x * 2 }) +// fab := either.Right[error](N.Mul(2)) // fa := either.Right[error](21) // result := either.MonadAp(fab, fa) // Right(42) // @@ -81,7 +81,7 @@ func Ap[B, A any](fa Result[A]) Operator[func(A) B, B] { // // result := either.MonadMap( // either.Right[error](21), -// func(x int) int { return x * 2 }, +// N.Mul(2), // ) // Right(42) // //go:inline diff --git a/v2/result/either_test.go b/v2/result/either_test.go index a3364ac..ec04dba 100644 --- a/v2/result/either_test.go +++ b/v2/result/either_test.go @@ -66,7 +66,7 @@ func TestUnwrapError(t *testing.T) { func TestReduce(t *testing.T) { - s := S.Semigroup() + s := S.Semigroup assert.Equal(t, "foobar", F.Pipe1(Right("bar"), Reduce(s.Concat, "foo"))) assert.Equal(t, "foo", F.Pipe1(Left[string](errors.New("bar")), Reduce(s.Concat, "foo"))) diff --git a/v2/result/logger.go b/v2/result/logger.go index e004a3d..7e9873c 100644 --- a/v2/result/logger.go +++ b/v2/result/logger.go @@ -33,7 +33,7 @@ import ( // result := F.Pipe2( // either.Right[error](42), // logger("Processing"), -// either.Map(func(x int) int { return x * 2 }), +// either.Map(N.Mul(2)), // ) // // Logs: "Processing: 42" // // result is Right(84) diff --git a/v2/semigroup/semigroup_test.go b/v2/semigroup/semigroup_test.go index f8fb945..1f45232 100644 --- a/v2/semigroup/semigroup_test.go +++ b/v2/semigroup/semigroup_test.go @@ -393,21 +393,21 @@ func TestMapSemigroup(t *testing.T) { // Benchmark tests func BenchmarkFirst(b *testing.B) { first := First[int]() - for i := 0; i < b.N; i++ { + for b.Loop() { first.Concat(1, 2) } } func BenchmarkLast(b *testing.B) { last := Last[int]() - for i := 0; i < b.N; i++ { + for b.Loop() { last.Concat(1, 2) } } func BenchmarkMakeSemigroupAdd(b *testing.B) { add := MakeSemigroup(func(a, b int) int { return a + b }) - for i := 0; i < b.N; i++ { + for b.Loop() { add.Concat(1, 2) } } @@ -415,7 +415,7 @@ func BenchmarkMakeSemigroupAdd(b *testing.B) { func BenchmarkReverse(b *testing.B) { sub := MakeSemigroup(func(a, b int) int { return a - b }) reversed := Reverse(sub) - for i := 0; i < b.N; i++ { + for b.Loop() { reversed.Concat(10, 3) } } @@ -426,7 +426,7 @@ func BenchmarkConcatAll(b *testing.B) { arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { concatAll(0)(arr) } } @@ -440,7 +440,7 @@ func BenchmarkFunctionSemigroup(b *testing.B) { combined := funcSG.Concat(f, g) b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { combined("hello") } } diff --git a/v2/string/semigroup.go b/v2/string/semigroup.go index e1c000a..01a1b8f 100644 --- a/v2/string/semigroup.go +++ b/v2/string/semigroup.go @@ -25,6 +25,4 @@ func concat(left string, right string) string { return fmt.Sprintf("%s%s", left, right) } -func Semigroup() S.Semigroup[string] { - return S.MakeSemigroup(concat) -} +var Semigroup = S.MakeSemigroup(concat)