Skip to content

Commit

Permalink
fix: refactor either type (#102)
Browse files Browse the repository at this point in the history
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
  • Loading branch information
CarstenLeue committed Feb 7, 2024
1 parent 7daf65e commit 8150ae2
Show file tree
Hide file tree
Showing 18 changed files with 59 additions and 58 deletions.
2 changes: 1 addition & 1 deletion context/readerioeither/file/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,5 @@ func ExampleReadFile() {
fmt.Println(result())

// Output:
// Right[<nil>, string](Carsten)
// Right[string](Carsten)
}
5 changes: 1 addition & 4 deletions context/readerioeither/generic/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -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],
)
Expand Down
23 changes: 14 additions & 9 deletions either/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
}
6 changes: 0 additions & 6 deletions either/either_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 5 additions & 5 deletions either/examples_create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

}
4 changes: 2 additions & 2 deletions either/examples_extract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion io/generic/io.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
})
}

Expand Down
4 changes: 2 additions & 2 deletions io/logging_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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)() })
}
10 changes: 5 additions & 5 deletions ioeither/examples_create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

}
2 changes: 1 addition & 1 deletion ioeither/examples_do_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,5 @@ func ExampleIOEither_do() {
fmt.Println(b())

// Output:
// Right[<nil>, int](8)
// Right[int](8)
}
2 changes: 1 addition & 1 deletion ioeither/examples_extract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func ExampleIOEither_extraction() {
fmt.Println(valueFromIO)

// Output:
// Right[<nil>, int](42)
// Right[int](42)
// 42
// 42

Expand Down
16 changes: 8 additions & 8 deletions samples/mostly-adequate/chapter08_tupperware_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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)
}
4 changes: 2 additions & 2 deletions samples/mostly-adequate/chapter09_monadiconions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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>)

}

Expand Down
8 changes: 4 additions & 4 deletions samples/mostly-adequate/chapter11_transformagain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
8 changes: 4 additions & 4 deletions samples/mostly-adequate/chapter12_traversing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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() {
Expand All @@ -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)))
}
2 changes: 1 addition & 1 deletion samples/presentation/examples/example_either_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion samples/presentation/examples/example_sideeffect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

}

Expand Down

0 comments on commit 8150ae2

Please sign in to comment.