1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-08-10 22:31:32 +02:00

fix: refactor either type

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
Dr. Carsten Leue
2024-02-07 10:57:58 +01:00
parent 7daf65effc
commit 5899c5d95f
18 changed files with 59 additions and 58 deletions

View File

@@ -47,5 +47,5 @@ func ExampleReadFile() {
fmt.Println(result())
// Output:
// Right[<nil>, string](Carsten)
// Right[string](Carsten)
}

View File

@@ -182,10 +182,7 @@ func withCancelCauseFunc[
ma,
IOE.Swap[GIOA, func() E.Either[A, error]],
IOE.ChainFirstIOK[func() E.Either[A, error], func() any](func(err error) func() any {
return IO.MakeIO[func() any](func() any {
cancel(err)
return nil
})
return IO.FromImpure[func() any](func() { cancel(err) })
}),
IOE.Swap[func() E.Either[A, error], GIOA],
)

View File

@@ -23,17 +23,16 @@ type (
// Either defines a data structure that logically holds either an E or an A. The flag discriminates the cases
Either[E, A any] struct {
isLeft bool
left E
right A
value any
}
)
// String prints some debug info for the object
func (s Either[E, A]) String() string {
if s.isLeft {
return fmt.Sprintf("Left[%T, %T](%v)", s.left, s.right, s.left)
return fmt.Sprintf("Left[%T](%v)", s.value, s.value)
}
return fmt.Sprintf("Right[%T, %T](%v)", s.left, s.right, s.right)
return fmt.Sprintf("Right[%T](%v)", s.value, s.value)
}
// Format prints some debug info for the object
@@ -58,23 +57,29 @@ func IsRight[E, A any](val Either[E, A]) bool {
// Left creates a new instance of an [Either] representing the left value.
func Left[A, E any](value E) Either[E, A] {
return Either[E, A]{isLeft: true, left: value}
return Either[E, A]{true, value}
}
// Right creates a new instance of an [Either] representing the right value.
func Right[E, A any](value A) Either[E, A] {
return Either[E, A]{isLeft: false, right: value}
return Either[E, A]{false, value}
}
// MonadFold extracts the values from an [Either] by invoking the [onLeft] callback or the [onRight] callback depending on the case
func MonadFold[E, A, B any](ma Either[E, A], onLeft func(e E) B, onRight func(a A) B) B {
if ma.isLeft {
return onLeft(ma.left)
return onLeft(ma.value.(E))
}
return onRight(ma.right)
return onRight(ma.value.(A))
}
// Unwrap converts an [Either] into the idiomatic tuple
func Unwrap[E, A any](ma Either[E, A]) (A, E) {
return ma.right, ma.left
if ma.isLeft {
var a A
return a, ma.value.(E)
} else {
var e E
return ma.value.(A), e
}
}

View File

@@ -26,12 +26,6 @@ import (
"github.com/stretchr/testify/assert"
)
func TestDefault(t *testing.T) {
var e Either[error, string]
assert.Equal(t, Of[error](""), e)
}
func TestIsLeft(t *testing.T) {
err := errors.New("Some error")
withError := Left[string](err)

View File

@@ -48,11 +48,11 @@ func ExampleEither_creation() {
fmt.Println(rightFromPred)
// Output:
// Left[*errors.errorString, string](some error)
// Right[<nil>, string](value)
// Left[*errors.errorString, *string](value was nil)
// Left[*errors.errorString](some error)
// Right[string](value)
// Left[*errors.errorString](value was nil)
// true
// Left[*errors.errorString, int](3 is an odd number)
// Right[<nil>, int](4)
// Left[*errors.errorString](3 is an odd number)
// Right[int](4)
}

View File

@@ -53,8 +53,8 @@ func ExampleEither_extraction() {
fmt.Println(doubleFromRightBis)
// Output:
// Left[*errors.errorString, int](Division by Zero!)
// Right[<nil>, int](10)
// Left[*errors.errorString](Division by Zero!)
// Right[int](10)
// 0
// 10
// 0

View File

@@ -25,6 +25,11 @@ import (
T "github.com/IBM/fp-go/tuple"
)
var (
// undefined represents an undefined value
undefined = struct{}{}
)
// type IO[A any] = func() A
func MakeIO[GA ~func() A, A any](f func() A) GA {
@@ -43,7 +48,7 @@ func FromIO[GA ~func() A, A any](a GA) GA {
func FromImpure[GA ~func() any, IMP ~func()](f IMP) GA {
return MakeIO[GA](func() any {
f()
return nil
return undefined
})
}

View File

@@ -27,7 +27,7 @@ func TestLogger(t *testing.T) {
lio := l("out")
assert.Equal(t, nil, lio(10)())
assert.NotPanics(t, func() { lio(10)() })
}
func TestLogf(t *testing.T) {
@@ -36,5 +36,5 @@ func TestLogf(t *testing.T) {
lio := l("Value is %d")
assert.Equal(t, nil, lio(10)())
assert.NotPanics(t, func() { lio(10)() })
}

View File

@@ -48,10 +48,10 @@ func ExampleIOEither_creation() {
fmt.Println(rightFromPred())
// Output:
// Left[*errors.errorString, string](some error)
// Right[<nil>, string](value)
// Right[<nil>, int](42)
// Left[*errors.errorString, int](3 is an odd number)
// Right[<nil>, int](4)
// Left[*errors.errorString](some error)
// Right[string](value)
// Right[int](42)
// Left[*errors.errorString](3 is an odd number)
// Right[int](4)
}

View File

@@ -53,5 +53,5 @@ func ExampleIOEither_do() {
fmt.Println(b())
// Output:
// Right[<nil>, int](8)
// Right[int](8)
}

View File

@@ -38,7 +38,7 @@ func ExampleIOEither_extraction() {
fmt.Println(valueFromIO)
// Output:
// Right[<nil>, int](42)
// Right[int](42)
// 42
// 42

View File

@@ -196,8 +196,8 @@ func Example_getAge() {
fmt.Println(zoltar(MakeUser("2005-12-12")))
// Output:
// Right[<nil>, float64](6472)
// Left[*time.ParseError, float64](parsing time "July 4, 2001" as "2006-01-02": cannot parse "July 4, 2001" as "2006")
// Right[float64](6472)
// Left[*time.ParseError](parsing time "July 4, 2001" as "2006-01-02": cannot parse "July 4, 2001" as "2006")
// If you survive, you will be 6837
}
@@ -235,8 +235,8 @@ func Example_solution08C() {
fmt.Println(eitherWelcome(theresa08))
// Output:
// Left[*errors.errorString, string](your account is not active)
// Right[<nil>, string](Welcome Theresa)
// Left[*errors.errorString](your account is not active)
// Right[string](Welcome Theresa)
}
func Example_solution08D() {
@@ -269,8 +269,8 @@ func Example_solution08D() {
fmt.Println(register(yi08)())
// Output:
// Right[<nil>, string](Gary)
// Left[*errors.errorString, <nil>](Your name Yi is larger than 3 characters)
// Right[<nil>, string](Welcome Albert)
// Left[*errors.errorString, string](Your name Yi is larger than 3 characters)
// Right[string](Gary)
// Left[*errors.errorString](Your name Yi is larger than 3 characters)
// Right[string](Welcome Albert)
// Left[*errors.errorString](Your name Yi is larger than 3 characters)
}

View File

@@ -181,6 +181,6 @@ func Example_solution09C() {
fmt.Println(joinMailingList("notanemail")())
// Output:
// Right[<nil>, string](sleepy@grandpa.net)
// Left[*errors.errorString, string](email notanemail is invalid)
// Right[string](sleepy@grandpa.net)
// Left[*errors.errorString](email notanemail is invalid)
}

View File

@@ -117,7 +117,7 @@ func Example_renderPage() {
fmt.Println(res(context.TODO())())
// Output:
// Right[<nil>, string](<div>Destinations: [qui est esse], Events: [ea molestias quasi exercitationem repellat qui ipsa sit aut]</div>)
// Right[string](<div>Destinations: [qui est esse], Events: [ea molestias quasi exercitationem repellat qui ipsa sit aut]</div>)
}

View File

@@ -63,10 +63,10 @@ func Example_solution11B() {
fmt.Println(findByNameID(4)())
// Output:
// Right[<nil>, string](Albert)
// Right[<nil>, string](Gary)
// Right[<nil>, string](Theresa)
// Left[*errors.errorString, string](user 4 not found)
// Right[string](Albert)
// Right[string](Gary)
// Right[string](Theresa)
// Left[*errors.errorString](user 4 not found)
}
func Example_solution11C() {

View File

@@ -60,7 +60,7 @@ func Example_solution12A() {
fmt.Println(getJsons(routes)())
// Output:
// Right[<nil>, map[string]string](map[/:json for / /about:json for /about])
// Right[map[string]string](map[/:json for / /about:json for /about])
}
func Example_solution12B() {
@@ -74,8 +74,8 @@ func Example_solution12B() {
fmt.Println(startGame(A.From(playerAlbert, Player{Id: 4})))
// Output:
// Right[<nil>, string](Game started)
// Left[*errors.errorString, string](player 4 must have a name)
// Right[string](Game started)
// Left[*errors.errorString](player 4 must have a name)
}
func Example_solution12C() {
@@ -94,5 +94,5 @@ func Example_solution12C() {
fmt.Println(readFirst())
// Output:
// Right[<nil>, option.Option[string]](Some[string](content of file1 (utf-8)))
// Right[option.Option[string]](Some[string](content of file1 (utf-8)))
}

View File

@@ -48,7 +48,7 @@ func Example_either_monad() {
fmt.Println(makeUrl("8080"))
// Output:
// Right[<nil>, string](http://localhost:8080)
// Right[string](http://localhost:8080)
}
func Example_either_idiomatic() {

View File

@@ -64,7 +64,7 @@ func Example_io_flow() {
fmt.Println(result())
// Output:
// Right[<nil>, string](Text: Some data, Number: 10)
// Right[string](Text: Some data, Number: 10)
}