Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Fold function to Result monad #42

Merged
merged 7 commits into from
Jun 22, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ jobs:
stable: false
- uses: actions/checkout@v2
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@v5
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update to newer version as I got the following linting error

func Result[T].{{func_name}} is unused (unused)

regarding those functions

with:
args: --timeout 120s --max-same-issues 50
28 changes: 28 additions & 0 deletions fold.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package mo

// Foldable represents a type that can be folded into a single value
// based on its state.
//
// - T: the type of the value in the failure state (e.g., an error type).
// - U: the type of the value in the success state.
type Foldable[T any, U any] interface {
left() T
right() U
isLeft() bool
}

// Fold applies one of the two functions based on the state of the Foldable type,
// and it returns the result of applying either successFunc or failureFunc.
//
// - T: the type of the failure value (e.g., an error type)
// - U: the type of the success value
// - R: the type of the return value from the folding functions
//
// successFunc is applied when the Foldable is in the success state (i.e., isLeft() is false).
// failureFunc is applied when the Foldable is in the failure state (i.e., isLeft() is true).
func Fold[T, U, R any](f Foldable[T, U], successFunc func(U) R, failureFunc func(T) R) R {
if f.isLeft() {
return failureFunc(f.left())
}
return successFunc(f.right())
}
15 changes: 15 additions & 0 deletions result.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,18 @@ func (o *Result[T]) UnmarshalJSON(data []byte) error {
o.isErr = false
return nil
}

// left returns the error if the Result is an error, otherwise nil
func (r Result[T]) left() error {
return r.err
}

// right returns the value if the Result is a success, otherwise the zero value of T
func (r Result[T]) right() T {
return r.value
}

// isLeft returns true if the Result represents an error state.
func (r Result[T]) isLeft() bool {
return r.isErr
}
40 changes: 40 additions & 0 deletions result_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,46 @@ func TestResultMatch(t *testing.T) {
is.Equal(Result[int]{value: 0, isErr: true, err: assert.AnError}, opt2)
}

// TestFoldSuccess tests the Fold method with a successful result.
func TestFoldSuccess(t *testing.T) {
result := Result[int]{value: 42, isErr: false, err: nil}

successFunc := func(value int) string {
return fmt.Sprintf("Success: %v", value)
}
failureFunc := func(err error) string {
return fmt.Sprintf("Failure: %v", err)
}

folded := Fold[error, int, string](result, successFunc, failureFunc)
expected := "Success: 42"

if folded != expected {
t.Errorf("Expected %q, got %q", expected, folded)
}
}

// TestFoldFailure tests the Fold method with a failure result.
func TestFoldFailure(t *testing.T) {
expectedError := assert.AnError
result := Result[int]{value: 0, isErr: true, err: expectedError}

successFunc := func(value int) string {
return fmt.Sprintf("Success: %v", value)
}
failureFunc := func(err error) string {
if err == expectedError {
return "Expected error occurred"
}
return fmt.Sprintf("Failure: %v", err)
}

folded := Fold[error, int, string](result, successFunc, failureFunc)
expected := "Expected error occurred"

assert.Equal(t, expected, folded)
}

func TestResultMap(t *testing.T) {
is := assert.New(t)

Expand Down