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:
@@ -47,5 +47,5 @@ func ExampleReadFile() {
|
||||
fmt.Println(result())
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, string](Carsten)
|
||||
// Right[string](Carsten)
|
||||
}
|
||||
|
@@ -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],
|
||||
)
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -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)() })
|
||||
}
|
||||
|
@@ -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)
|
||||
|
||||
}
|
||||
|
@@ -53,5 +53,5 @@ func ExampleIOEither_do() {
|
||||
fmt.Println(b())
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, int](8)
|
||||
// Right[int](8)
|
||||
}
|
||||
|
@@ -38,7 +38,7 @@ func ExampleIOEither_extraction() {
|
||||
fmt.Println(valueFromIO)
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, int](42)
|
||||
// Right[int](42)
|
||||
// 42
|
||||
// 42
|
||||
|
||||
|
@@ -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)
|
||||
}
|
||||
|
@@ -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)
|
||||
}
|
||||
|
@@ -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>)
|
||||
|
||||
}
|
||||
|
||||
|
@@ -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() {
|
||||
|
@@ -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)))
|
||||
}
|
||||
|
@@ -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() {
|
||||
|
@@ -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)
|
||||
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user