1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-11-25 22:21:49 +02:00

fix: ChainReaderK

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
Dr. Carsten Leue
2025-11-22 10:39:56 +01:00
parent 4e9998b645
commit d8ab6b0ce5
2 changed files with 53 additions and 4 deletions

View File

@@ -365,13 +365,13 @@ func Asks[R, A any](r Reader[R, A]) ReaderResult[R, A] {
//
// parseUser := func(data string) result.Result[User] { ... }
// result := readerresult.MonadChainEitherK(getUserDataRR, parseUser)
func MonadChainEitherK[R, A, B any](ma ReaderResult[R, A], f result.Kleisli[A, B]) ReaderResult[R, B] {
func MonadChainEitherK[R, A, B any](ma ReaderResult[R, A], f RES.Kleisli[A, B]) ReaderResult[R, B] {
return func(r R) (B, error) {
a, err := ma(r)
if err != nil {
return result.Left[B](err)
}
return f(a)
return RES.Unwrap(f(a))
}
}
@@ -384,10 +384,40 @@ func MonadChainEitherK[R, A, B any](ma ReaderResult[R, A], f result.Kleisli[A, B
// result := F.Pipe1(getUserDataRR, readerresult.ChainEitherK[Config](parseUser))
//
//go:inline
func ChainEitherK[R, A, B any](f result.Kleisli[A, B]) Operator[R, A, B] {
func ChainEitherK[R, A, B any](f RES.Kleisli[A, B]) Operator[R, A, B] {
return function.Bind2nd(MonadChainEitherK[R, A, B], f)
}
// MonadChainReaderK chains a ReaderResult with a function that returns a plain Result.
// This is useful for integrating functions that don't need environment access.
//
// Example:
//
// parseUser := func(data string) result.Result[User] { ... }
// result := readerresult.MonadChainReaderK(getUserDataRR, parseUser)
func MonadChainReaderK[R, A, B any](ma ReaderResult[R, A], f result.Kleisli[A, B]) ReaderResult[R, B] {
return func(r R) (B, error) {
a, err := ma(r)
if err != nil {
return result.Left[B](err)
}
return f(a)
}
}
// ChainReaderK is the curried version of MonadChainEitherK.
// It lifts a Result-returning function into a ReaderResult operator.
//
// Example:
//
// parseUser := func(data string) result.Result[User] { ... }
// result := F.Pipe1(getUserDataRR, readerresult.ChainReaderK[Config](parseUser))
//
//go:inline
func ChainReaderK[R, A, B any](f result.Kleisli[A, B]) Operator[R, A, B] {
return function.Bind2nd(MonadChainReaderK[R, A, B], f)
}
// ChainOptionK chains with a function that returns an Option, converting None to an error.
// This is useful for integrating functions that return optional values.
//

View File

@@ -24,6 +24,7 @@ import (
"github.com/IBM/fp-go/v2/internal/utils"
"github.com/IBM/fp-go/v2/reader"
"github.com/IBM/fp-go/v2/result"
RES "github.com/IBM/fp-go/v2/result"
"github.com/stretchr/testify/assert"
)
@@ -271,7 +272,7 @@ func TestAsks(t *testing.T) {
assert.Equal(t, 7, v)
}
func TestChainEitherK(t *testing.T) {
func TestChainReaderK(t *testing.T) {
parseInt := func(s string) (int, error) {
if s == "42" {
return 42, nil
@@ -279,6 +280,24 @@ func TestChainEitherK(t *testing.T) {
return 0, errors.New("parse error")
}
chain := ChainReaderK[MyContext](parseInt)
v, err := F.Pipe1(Of[MyContext]("42"), chain)(defaultContext)
assert.NoError(t, err)
assert.Equal(t, 42, v)
_, err = F.Pipe1(Of[MyContext]("invalid"), chain)(defaultContext)
assert.Error(t, err)
}
func TestChainEitherK(t *testing.T) {
parseInt := func(s string) RES.Result[int] {
if s == "42" {
return RES.Of(42)
}
return RES.Left[int](errors.New("parse error"))
}
chain := ChainEitherK[MyContext](parseInt)
v, err := F.Pipe1(Of[MyContext]("42"), chain)(defaultContext)