-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from repeale/feat/option-implementation
feat: Option implementation
- Loading branch information
Showing
4 changed files
with
197 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package fp | ||
|
||
// Callback function that returns a specific value type | ||
type Lazy[T any] func() T | ||
|
||
// Callback function that takes an argument and return a value of the same type | ||
type LazyVal[T any] func(x T) T |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package opt | ||
|
||
import ( | ||
"github.com/repeale/fp-go" | ||
) | ||
|
||
// Base option struct | ||
type Option[T any] struct { | ||
value T | ||
hasValue bool | ||
} | ||
|
||
// Constructor for Option with a value | ||
func Some[T any](value T) Option[T] { | ||
return Option[T]{value, true} | ||
} | ||
|
||
// Constructor for Option without a value | ||
func None[T any]() Option[T] { | ||
return Option[T]{} | ||
} | ||
|
||
// Helper to check if the Option has a value | ||
func IsSome[T any](option Option[T]) bool { | ||
return option.hasValue | ||
} | ||
|
||
// Helper to check if the Option is missing the value | ||
func IsNone[T any](option Option[T]) bool { | ||
return !option.hasValue | ||
} | ||
|
||
// Extracts the value out of the Option, if it exists. Otherwise returns the function with a default value | ||
func GetOrElse[T any](onNone fp.Lazy[T]) func(Option[T]) T { | ||
return func(option Option[T]) T { | ||
|
||
if IsNone(option) { | ||
return onNone() | ||
} | ||
|
||
return option.value | ||
} | ||
} | ||
|
||
// Extracts the value out of the Option, if it exists, with a function. Otherwise returns the function with a default value | ||
func Match[T any](onNone fp.Lazy[T], onSome fp.LazyVal[T]) func(Option[T]) T { | ||
return func(option Option[T]) T { | ||
|
||
if IsNone(option) { | ||
return onNone() | ||
} | ||
|
||
return onSome(option.value) | ||
} | ||
} | ||
|
||
// Execute the function on the Option value if it exists. Otherwise return the empty Option itself | ||
func Map[T any](fn fp.LazyVal[T]) func(o Option[T]) Option[T] { | ||
return func(option Option[T]) Option[T] { | ||
|
||
if IsNone(option) { | ||
return None[T]() | ||
} | ||
|
||
return Some(fn(option.value)) | ||
} | ||
} | ||
|
||
// Execute a function that returns an Option on the Option value if it exists. Otherwise return the empty Option itself | ||
func Chain[A any, B any](fn func(a A) Option[B]) func(Option[A]) Option[B] { | ||
return func(a Option[A]) Option[B] { | ||
|
||
if IsNone(a) { | ||
return None[B]() | ||
} | ||
|
||
return fn(a.value) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package opt | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func TestSome(t *testing.T) { | ||
res := Some("val") | ||
if res.hasValue != true { | ||
t.Error("Some should return a struct with hasValue set to true. Received:", res.hasValue) | ||
} | ||
} | ||
|
||
func TestNone(t *testing.T) { | ||
res := None[string]() | ||
if res.hasValue != false { | ||
t.Error("None should return a struct with hasValue set to false. Received:", res.hasValue) | ||
} | ||
} | ||
|
||
func TestIsSome_Some(t *testing.T) { | ||
res := IsSome(Some("value")) | ||
if res != true { | ||
t.Error("IsSome should return true. Received:", res) | ||
} | ||
} | ||
func TestIsSome_None(t *testing.T) { | ||
res := IsSome(None[string]()) | ||
if res != false { | ||
t.Error("IsSome should return false. Received:", res) | ||
} | ||
} | ||
|
||
func TestIsNone_Some(t *testing.T) { | ||
res := IsNone(None[string]()) | ||
if res != true { | ||
t.Error("IsNone should return true. Received:", res) | ||
} | ||
} | ||
func TestIsNone_None(t *testing.T) { | ||
res := IsNone(Some("value")) | ||
if res != false { | ||
t.Error("IsNone should return false. Received:", res) | ||
} | ||
} | ||
|
||
func TestGetOrElse_Some(t *testing.T) { | ||
res := GetOrElse(func() string { return "fail" })(Some("val")) | ||
if res != "val" { | ||
t.Error("GetOrElse should return the Some value. Received:", res) | ||
} | ||
} | ||
|
||
func TestGetOrElse_None(t *testing.T) { | ||
res := GetOrElse(func() string { return "elseValue" })(None[string]()) | ||
if res != "elseValue" { | ||
t.Error("GetOrElse should return the onNone() value. Received:", res) | ||
} | ||
} | ||
|
||
func TestMatch_onSome(t *testing.T) { | ||
res := Match(func() string { return "onNone" }, func(x string) string { return x + x })(Some("val")) | ||
if res != "valval" { | ||
t.Error("Match should return the onSome() value. Received:", res) | ||
} | ||
} | ||
|
||
func TestMatch_onNone(t *testing.T) { | ||
res := Match(func() string { return "onNone" }, func(x string) string { return x + x })(None[string]()) | ||
if res != "onNone" { | ||
t.Error("Match should return the onNone() return value. Received:", res) | ||
} | ||
} | ||
|
||
func TestMap_Some(t *testing.T) { | ||
res := Map(func(x string) string { return x + x })(Some("val")) | ||
if res.value != "valval" { | ||
t.Error("Map should return the result of the callback function. Received:", res.value) | ||
} | ||
} | ||
|
||
func TestMap_None(t *testing.T) { | ||
res := Map(func(x string) string { return x + x })(None[string]()) | ||
if res.hasValue != false { | ||
t.Error("Map should return a None value. Received:", res.value) | ||
} | ||
} | ||
|
||
func TestChain_Some(t *testing.T) { | ||
res := Chain(func(x string) Option[string] { return Some(x + x) })(Some("val")) | ||
if res.hasValue != true { | ||
t.Error("Chain should return a Some of string. Received:", res.value) | ||
} | ||
} | ||
func TestChain_None(t *testing.T) { | ||
res := Chain(func(x string) Option[string] { return Some(x + x) })(None[string]()) | ||
if res.hasValue != false { | ||
t.Error("Chain should return a None value. Received:", res.value) | ||
} | ||
} |