From 8150ae2a68360ace3bb631dc630e42053eea46cd Mon Sep 17 00:00:00 2001 From: Carsten Leue Date: Wed, 7 Feb 2024 11:03:20 +0100 Subject: [PATCH] fix: refactor either type (#102) Signed-off-by: Dr. Carsten Leue --- context/readerioeither/file/file_test.go | 2 +- context/readerioeither/generic/reader.go | 5 +--- either/core.go | 23 +++++++++++-------- either/either_test.go | 6 ----- either/examples_create_test.go | 10 ++++---- either/examples_extract_test.go | 4 ++-- io/generic/io.go | 7 +++++- io/logging_test.go | 4 ++-- ioeither/examples_create_test.go | 10 ++++---- ioeither/examples_do_test.go | 2 +- ioeither/examples_extract_test.go | 2 +- .../chapter08_tupperware_test.go | 16 ++++++------- .../chapter09_monadiconions_test.go | 4 ++-- .../chapter10_applicativefunctor_test.go | 2 +- .../chapter11_transformagain_test.go | 8 +++---- .../chapter12_traversing_test.go | 8 +++---- .../examples/example_either_test.go | 2 +- .../examples/example_sideeffect_test.go | 2 +- 18 files changed, 59 insertions(+), 58 deletions(-) diff --git a/context/readerioeither/file/file_test.go b/context/readerioeither/file/file_test.go index b930700..fc9c830 100644 --- a/context/readerioeither/file/file_test.go +++ b/context/readerioeither/file/file_test.go @@ -47,5 +47,5 @@ func ExampleReadFile() { fmt.Println(result()) // Output: - // Right[, string](Carsten) + // Right[string](Carsten) } diff --git a/context/readerioeither/generic/reader.go b/context/readerioeither/generic/reader.go index b583319..788fd70 100644 --- a/context/readerioeither/generic/reader.go +++ b/context/readerioeither/generic/reader.go @@ -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], ) diff --git a/either/core.go b/either/core.go index 7602792..b56978e 100644 --- a/either/core.go +++ b/either/core.go @@ -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 + } } diff --git a/either/either_test.go b/either/either_test.go index 85e6755..0db9b2e 100644 --- a/either/either_test.go +++ b/either/either_test.go @@ -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) diff --git a/either/examples_create_test.go b/either/examples_create_test.go index 811a433..369bca2 100644 --- a/either/examples_create_test.go +++ b/either/examples_create_test.go @@ -48,11 +48,11 @@ func ExampleEither_creation() { fmt.Println(rightFromPred) // Output: - // Left[*errors.errorString, string](some error) - // Right[, 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[, int](4) + // Left[*errors.errorString](3 is an odd number) + // Right[int](4) } diff --git a/either/examples_extract_test.go b/either/examples_extract_test.go index 4436b2c..0988100 100644 --- a/either/examples_extract_test.go +++ b/either/examples_extract_test.go @@ -53,8 +53,8 @@ func ExampleEither_extraction() { fmt.Println(doubleFromRightBis) // Output: - // Left[*errors.errorString, int](Division by Zero!) - // Right[, int](10) + // Left[*errors.errorString](Division by Zero!) + // Right[int](10) // 0 // 10 // 0 diff --git a/io/generic/io.go b/io/generic/io.go index 1e0bef6..cbfbe9e 100644 --- a/io/generic/io.go +++ b/io/generic/io.go @@ -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 }) } diff --git a/io/logging_test.go b/io/logging_test.go index 52f5fb3..baa048f 100644 --- a/io/logging_test.go +++ b/io/logging_test.go @@ -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)() }) } diff --git a/ioeither/examples_create_test.go b/ioeither/examples_create_test.go index fb6737e..f6e99a6 100644 --- a/ioeither/examples_create_test.go +++ b/ioeither/examples_create_test.go @@ -48,10 +48,10 @@ func ExampleIOEither_creation() { fmt.Println(rightFromPred()) // Output: - // Left[*errors.errorString, string](some error) - // Right[, string](value) - // Right[, int](42) - // Left[*errors.errorString, int](3 is an odd number) - // Right[, int](4) + // Left[*errors.errorString](some error) + // Right[string](value) + // Right[int](42) + // Left[*errors.errorString](3 is an odd number) + // Right[int](4) } diff --git a/ioeither/examples_do_test.go b/ioeither/examples_do_test.go index 9424432..f1b699b 100644 --- a/ioeither/examples_do_test.go +++ b/ioeither/examples_do_test.go @@ -53,5 +53,5 @@ func ExampleIOEither_do() { fmt.Println(b()) // Output: - // Right[, int](8) + // Right[int](8) } diff --git a/ioeither/examples_extract_test.go b/ioeither/examples_extract_test.go index 728db07..9ecf86c 100644 --- a/ioeither/examples_extract_test.go +++ b/ioeither/examples_extract_test.go @@ -38,7 +38,7 @@ func ExampleIOEither_extraction() { fmt.Println(valueFromIO) // Output: - // Right[, int](42) + // Right[int](42) // 42 // 42 diff --git a/samples/mostly-adequate/chapter08_tupperware_test.go b/samples/mostly-adequate/chapter08_tupperware_test.go index faba391..e6fbdc3 100644 --- a/samples/mostly-adequate/chapter08_tupperware_test.go +++ b/samples/mostly-adequate/chapter08_tupperware_test.go @@ -196,8 +196,8 @@ func Example_getAge() { fmt.Println(zoltar(MakeUser("2005-12-12"))) // Output: - // Right[, 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[, 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[, string](Gary) - // Left[*errors.errorString, ](Your name Yi is larger than 3 characters) - // Right[, 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) } diff --git a/samples/mostly-adequate/chapter09_monadiconions_test.go b/samples/mostly-adequate/chapter09_monadiconions_test.go index 5628e98..5315c19 100644 --- a/samples/mostly-adequate/chapter09_monadiconions_test.go +++ b/samples/mostly-adequate/chapter09_monadiconions_test.go @@ -181,6 +181,6 @@ func Example_solution09C() { fmt.Println(joinMailingList("notanemail")()) // Output: - // Right[, string](sleepy@grandpa.net) - // Left[*errors.errorString, string](email notanemail is invalid) + // Right[string](sleepy@grandpa.net) + // Left[*errors.errorString](email notanemail is invalid) } diff --git a/samples/mostly-adequate/chapter10_applicativefunctor_test.go b/samples/mostly-adequate/chapter10_applicativefunctor_test.go index 35dcbb3..9a1702d 100644 --- a/samples/mostly-adequate/chapter10_applicativefunctor_test.go +++ b/samples/mostly-adequate/chapter10_applicativefunctor_test.go @@ -117,7 +117,7 @@ func Example_renderPage() { fmt.Println(res(context.TODO())()) // Output: - // Right[, string](
Destinations: [qui est esse], Events: [ea molestias quasi exercitationem repellat qui ipsa sit aut]
) + // Right[string](
Destinations: [qui est esse], Events: [ea molestias quasi exercitationem repellat qui ipsa sit aut]
) } diff --git a/samples/mostly-adequate/chapter11_transformagain_test.go b/samples/mostly-adequate/chapter11_transformagain_test.go index 3ac312d..8fd1984 100644 --- a/samples/mostly-adequate/chapter11_transformagain_test.go +++ b/samples/mostly-adequate/chapter11_transformagain_test.go @@ -63,10 +63,10 @@ func Example_solution11B() { fmt.Println(findByNameID(4)()) // Output: - // Right[, string](Albert) - // Right[, string](Gary) - // Right[, 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() { diff --git a/samples/mostly-adequate/chapter12_traversing_test.go b/samples/mostly-adequate/chapter12_traversing_test.go index e5db267..82b15b2 100644 --- a/samples/mostly-adequate/chapter12_traversing_test.go +++ b/samples/mostly-adequate/chapter12_traversing_test.go @@ -60,7 +60,7 @@ func Example_solution12A() { fmt.Println(getJsons(routes)()) // Output: - // Right[, 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[, 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[, option.Option[string]](Some[string](content of file1 (utf-8))) + // Right[option.Option[string]](Some[string](content of file1 (utf-8))) } diff --git a/samples/presentation/examples/example_either_test.go b/samples/presentation/examples/example_either_test.go index f3785ac..b7489ac 100644 --- a/samples/presentation/examples/example_either_test.go +++ b/samples/presentation/examples/example_either_test.go @@ -48,7 +48,7 @@ func Example_either_monad() { fmt.Println(makeUrl("8080")) // Output: - // Right[, string](http://localhost:8080) + // Right[string](http://localhost:8080) } func Example_either_idiomatic() { diff --git a/samples/presentation/examples/example_sideeffect_test.go b/samples/presentation/examples/example_sideeffect_test.go index 04e7533..ccb5637 100644 --- a/samples/presentation/examples/example_sideeffect_test.go +++ b/samples/presentation/examples/example_sideeffect_test.go @@ -64,7 +64,7 @@ func Example_io_flow() { fmt.Println(result()) // Output: - // Right[, string](Text: Some data, Number: 10) + // Right[string](Text: Some data, Number: 10) }