From f1a38714d462abd23ce598c211dc333e1fd75f35 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Thu, 20 Jun 2024 15:03:57 -0700 Subject: [PATCH] fn: add additional utility methods for Result[T] `NewResult` makes it easy to wrap a normal function call in a result value. `Err` can be used to check the error case of the result without unpacking the entire thing. `AndThen2` allows a caller to compose a function on two results values, with the closure only executing if both values are non-error. --- fn/result.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/fn/result.go b/fn/result.go index 11d2d82a4..cb459bdc8 100644 --- a/fn/result.go +++ b/fn/result.go @@ -10,6 +10,15 @@ type Result[T any] struct { Either[T, error] } +// NewResult creates a new result from a (value, error) tuple. +func NewResult[T any](val T, err error) Result[T] { + if err != nil { + return Err[T](err) + } + + return Ok(val) +} + // Ok creates a new Result with a success value. func Ok[T any](val T) Result[T] { return Result[T]{Either: NewLeft[T, error](val)} @@ -33,6 +42,11 @@ func (r Result[T]) Unpack() (T, error) { return r.left.UnwrapOr(zero), r.right.UnwrapOr(nil) } +// Err exposes the underlying error of the result type as a normal error type. +func (r Result[T]) Err() error { + return r.right.some +} + // IsOk returns true if the Result is a success value. func (r Result[T]) IsOk() bool { return r.IsLeft() @@ -140,3 +154,15 @@ func FlatMap[A, B any](r Result[A], f func(A) Result[B]) Result[B] { func AndThen[A, B any](r Result[A], f func(A) Result[B]) Result[B] { return FlatMap(r, f) } + +// AndThen2 applies a function that returns a Result[C] to the success values +// of two Result types if both exist. +func AndThen2[A, B, C any](ra Result[A], rb Result[B], + f func(A, B) Result[C]) Result[C] { + + return AndThen(ra, func(a A) Result[C] { + return AndThen(rb, func(b B) Result[C] { + return f(a, b) + }) + }) +}