1
0
mirror of https://github.com/IBM/fp-go.git synced 2026-01-11 00:42:26 +02:00

Compare commits

..

2 Commits

Author SHA1 Message Date
Carsten Leue
86a260a204 Introduce IORef (#150)
* fix: add ioref and tests

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: better tests

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

---------

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2026-01-04 16:45:40 +01:00
lif
6a6b982779 feat: Add OrElse to ioeither for error recovery (#148)
* feat: add OrElse to ioeither for error recovery

Add OrElse function to both v1 and v2 ioeither packages for error recovery.
This allows recovering from a Left value by applying a function to the error
and returning a new IOEither, consistent with the Either package's API.

- Add OrElse to ioeither/generic/ioeither.go
- Add OrElse wrapper to ioeither/ioeither.go
- Add OrElse to v2/ioeither/generic/ioeither.go
- Add OrElse to v2/ioeither/ioeither.go
- Add comprehensive tests for both v1 and v2

Closes #146

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: majiayu000 <1835304752@qq.com>

* chore(v2): drop ioeither OrElse addition

---------

Signed-off-by: majiayu000 <1835304752@qq.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 16:41:13 +01:00
3 changed files with 51 additions and 0 deletions

View File

@@ -369,6 +369,11 @@ func ToIOOption[GA ~func() O.Option[A], GEA ~func() ET.Either[E, A], E, A any](i
)
}
// OrElse returns the original IOEither if it is a Right, otherwise it applies the given function to the error and returns the result.
func OrElse[GA ~func() ET.Either[E, A], E, A any](onLeft func(E) GA) func(GA) GA {
return eithert.OrElse(IO.MonadChain[GA, GA, ET.Either[E, A], ET.Either[E, A]], IO.Of[GA, ET.Either[E, A]], onLeft)
}
func FromIOOption[GEA ~func() ET.Either[E, A], GA ~func() O.Option[A], E, A any](onNone func() E) func(ioo GA) GEA {
return IO.Map[GA, GEA](ET.FromOption[A](onNone))
}

View File

@@ -266,6 +266,11 @@ func Alt[E, A any](second L.Lazy[IOEither[E, A]]) func(IOEither[E, A]) IOEither[
return G.Alt(second)
}
// OrElse returns the original IOEither if it is a Right, otherwise it applies the given function to the error and returns the result.
func OrElse[E, A any](onLeft func(E) IOEither[E, A]) func(IOEither[E, A]) IOEither[E, A] {
return G.OrElse[IOEither[E, A]](onLeft)
}
func MonadFlap[E, B, A any](fab IOEither[E, func(A) B], a A) IOEither[E, B] {
return G.MonadFlap[IOEither[E, func(A) B], IOEither[E, B]](fab, a)
}

View File

@@ -134,3 +134,44 @@ func TestApSecond(t *testing.T) {
assert.Equal(t, E.Of[error]("b"), x())
}
func TestOrElse(t *testing.T) {
// Test that OrElse recovers from a Left
recover := OrElse(func(err string) IOEither[string, int] {
return Right[string](42)
})
// When input is Left, should recover
leftResult := F.Pipe1(
Left[int]("error"),
recover,
)
assert.Equal(t, E.Right[string](42), leftResult())
// When input is Right, should pass through unchanged
rightResult := F.Pipe1(
Right[string](100),
recover,
)
assert.Equal(t, E.Right[string](100), rightResult())
// Test that OrElse can also return a Left (propagate different error)
recoverOrFail := OrElse(func(err string) IOEither[string, int] {
if err == "recoverable" {
return Right[string](0)
}
return Left[int]("unrecoverable: " + err)
})
recoverable := F.Pipe1(
Left[int]("recoverable"),
recoverOrFail,
)
assert.Equal(t, E.Right[string](0), recoverable())
unrecoverable := F.Pipe1(
Left[int]("fatal"),
recoverOrFail,
)
assert.Equal(t, E.Left[int]("unrecoverable: fatal"), unrecoverable())
}