mirror of
https://github.com/IBM/fp-go.git
synced 2025-11-23 22:14:53 +02:00
fix: modernize codebase
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
10
v2/README.md
10
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):**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -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)()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())())
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")))
|
||||
|
||||
@@ -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)
|
||||
|
||||
142
v2/either/validation.go
Normal file
142
v2/either/validation.go
Normal file
@@ -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]))
|
||||
})
|
||||
}
|
||||
}
|
||||
381
v2/either/validation_test.go
Normal file
381
v2/either/validation_test.go
Normal file
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }
|
||||
//
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
//
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 }),
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 })
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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]()))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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]] {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)())
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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)())
|
||||
|
||||
@@ -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]
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
)
|
||||
|
||||
func TestUnionMonoid(t *testing.T) {
|
||||
m := UnionMonoid[string](S.Semigroup())
|
||||
m := UnionMonoid[string](S.Semigroup)
|
||||
|
||||
e := Empty[string, string]()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user