mon

package
v1.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 13, 2026 License: MIT Imports: 2 Imported by: 0

README

mon

Monadic types for Go - Result and Option

The mon package provides functional programming monads: Result[T] for error handling and Option[T] for optional values. These types make error handling explicit and composable.

Quick Reference

By Category:

Installation

go get github.com/modfin/henry/mon

Result Type

Result[T] represents either a success value or an error. It forces explicit error handling.

Creating Results
Ok

Create a success result.

r := mon.Ok(42)
Err

Create an error result.

r := mon.Err[int](errors.New("something went wrong"))
TupleToResult / From

Convert (value, error) tuple to Result.

// From function that returns (T, error)
val, err := strconv.Atoi("42")
r := mon.TupleToResult(val, err)
// r is Ok(42) if err is nil, otherwise Err(err)

// Shorthand
r := mon.From(strconv.Atoi("42"))
Working with Results
IsOk / IsErr

Check state.

r := mon.Ok(42)
r.IsOk()   // true
r.IsErr()  // false
Unwrap

Get value or panic on error.

val := r.Unwrap()  // 42

// Error case - panics!
bad := mon.Err[int](errors.New("oops"))
bad.Unwrap()  // panic!
UnwrapOr

Get value or default.

val := r.UnwrapOr(0)        // 42
bad.UnwrapOr(0)             // 0 (default)
UnwrapOrElse

Get value or compute default.

val := bad.UnwrapOrElse(func() int {
    return expensiveFallback()
})
Expect

Unwrap with custom panic message.

val := r.Expect("should have a value")  // 42
bad.Expect("should have a value")       // panics with message
Transforming Results
Map

Transform success value.

r := mon.Ok(5)
doubled := r.Map(func(n int) int {
    return n * 2
})
// doubled = Ok(10)

// Error results pass through unchanged
bad := mon.Err[int](errors.New("oops"))
result := bad.Map(func(n int) int { return n * 2 })
// result still contains the error
MapErr

Transform error.

bad := mon.Err[int](errors.New("original"))
wrapped := bad.MapErr(func(err error) error {
    return fmt.Errorf("wrapped: %w", err)
})
FlatMap / Bind

Chain operations that return Results.

r := mon.Ok(5)
result := r.FlatMap(func(n int) mon.Result[int] {
    if n < 0 {
        return mon.Err[int](errors.New("negative"))
    }
    return mon.Ok(n * 2)
})
// result = Ok(10)
Or

Use alternative if error.

r1 := mon.Err[int](errors.New("failed"))
r2 := mon.Ok(42)
result := r1.Or(r2)
// result = Ok(42)
OrElse

Compute alternative if error.

result := r1.OrElse(func() mon.Result[int] {
    return fallbackOperation()
})
Collections of Results
Partition

Split into successes and failures.

results := []mon.Result[int]{
    mon.Ok(1),
    mon.Err[int](errors.New("bad")),
    mon.Ok(3),
    mon.Err[int](errors.New("worse")),
}

oks, errs := mon.Partition(results)
// oks = []int{1, 3}
// errs = []error{error1, error2}
Unwrap (collection)

Extract values or return first error.

results := []mon.Result[int]{
    mon.Ok(1),
    mon.Ok(2),
    mon.Ok(3),
}
vals, err := mon.Unwrap(results)
// vals = []int{1, 2, 3}, err = nil

// With an error
badResults := []mon.Result[int]{
    mon.Ok(1),
    mon.Err[int](errors.New("failed")),
    mon.Ok(3),
}
vals, err := mon.Unwrap(badResults)
// vals = nil, err = error

Option Type

Option[T] represents either a value or nothing (like nullable types).

Creating Options
Some

Create with a value.

o := mon.Some(42)
None

Create empty.

o := mon.None[int]()
FromPtr

Create from pointer.

val := 42
ptr := &val
o := mon.FromPtr(ptr)   // Some(42)

var nilPtr *int
o = mon.FromPtr(nilPtr) // None[int]()
Working with Options
IsSome / IsNone

Check state.

o := mon.Some(42)
o.IsSome()  // true
o.IsNone()  // false
Unwrap

Get value or panic.

val := o.Unwrap()  // 42

// None case
none := mon.None[int]()
none.Unwrap()  // panic!
UnwrapOr / UnwrapOrElse

Get value or default.

o.UnwrapOr(0)           // 42
mon.None[int]().UnwrapOr(0)  // 0

// With computation
mon.None[int]().UnwrapOrElse(func() int {
    return expensiveDefault()
})
Expect

Unwrap with message.

val := o.Expect("should have value")
Transforming Options
Map

Transform value if present.

o := mon.Some(5)
doubled := o.Map(func(n int) int {
    return n * 2
})
// doubled = Some(10)

// None passes through
mon.None[int]().Map(func(n int) int { return n * 2 })
// still None
FlatMap / Bind

Chain optional operations.

o := mon.Some(5)
result := o.FlatMap(func(n int) mon.Option[int] {
    if n < 0 {
        return mon.None[int]()
    }
    return mon.Some(n * 2)
})
// result = Some(10)
Filter

Convert to None if predicate fails.

o := mon.Some(5)
even := o.Filter(func(n int) bool {
    return n%2 == 0
})
// even = None[int]() (5 is odd)
Or / OrElse

Provide alternative.

none := mon.None[int]()
alt := mon.Some(42)
result := none.Or(alt)
// result = Some(42)

Common Patterns

Error Handling in Pipelines
import (
    "github.com/modfin/henry/mon"
    "github.com/modfin/henry/slicez"
)

// Parse URLs safely
func parseURLs(urls []string) ([]*url.URL, error) {
    results := slicez.Map(urls, func(s string) mon.Result[*url.URL] {
        u, err := url.Parse(s)
        return mon.From(u, err)
    })
    
    return mon.Unwrap(results)
}

// Usage
urls := []string{
    "https://example.com",
    "https://github.com",
    "bad url",
}

parsed, err := parseURLs(urls)
// parsed contains valid URLs, err is first parse error
Optional Values
func findUser(id int) mon.Option[User] {
    user, err := db.GetUser(id)
    if err != nil {
        return mon.None[User]()
    }
    return mon.Some(user)
}

// Usage
userOpt := findUser(42)
if user, ok := userOpt.UnwrapOr(User{}); ok {
    fmt.Println(user.Name)
}

// Or with default
user := findUser(42).UnwrapOr(guestUser)
Chaining Operations
result := fetchUser(id).
    FlatMap(func(u User) mon.Result[Profile] {
        return fetchProfile(u.ProfileID)
    }).
    Map(func(p Profile) Profile {
        p.LastSeen = time.Now()
        return p
    })

if result.IsErr() {
    log.Printf("Failed: %v", result.Err())
    return
}
profile := result.Unwrap()

Comparison with Standard Error Handling

Standard Go:

val1, err := step1()
if err != nil {
    return nil, err
}
val2, err := step2(val1)
if err != nil {
    return nil, err
}
return step3(val2)

With Result:

return step1().
    FlatMap(step2).
    FlatMap(step3)

When to Use

Use Result when:

  • Error handling is the primary concern
  • You want to defer error checking
  • Building complex pipelines

Use Option when:

  • Nullable values
  • Optional configuration
  • Caching/memoization

Use standard Go when:

  • Simple sequential code
  • Early returns are needed
  • Team prefers idiomatic Go

See Also

  • slicez - Use with Map to create collections of Results
  • chanz - Async pipelines with error handling

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Option

type Option[T any] struct {
	// contains filtered or unexported fields
}

Option is a container for an optional value of type T. If value exists, Option is of type Some. If the value is absent, Option is of type None.

func EmptyableToOption

func EmptyableToOption[T any](value T) Option[T]

EmptyableToOption builds a Some Option when value is not empty, or None.

func None

func None[T any]() Option[T]

None builds an Option when value is absent.

func PointerToOption

func PointerToOption[T any](value *T) Option[T]

PointerToOption builds a Some Option when value is not nil, or None.

func Some

func Some[T any](value T) Option[T]

Some builds an Option when value is present.

func TupleToOption

func TupleToOption[T any](value T, ok bool) Option[T]

TupleToOption builds a Some Option when second argument is true, or None.

func (Option[T]) FlatMap

func (o Option[T]) FlatMap(mapper func(value T) Option[T]) Option[T]

FlatMap executes the mapper function if value is present or returns None if absent.

func (Option[T]) ForEach

func (o Option[T]) ForEach(onValue func(value T))

ForEach executes the given side-effecting function of value is present.

func (Option[T]) Get

func (o Option[T]) Get() (T, bool)

Get returns value and presence.

func (Option[T]) Map

func (o Option[T]) Map(mapper func(value T) (T, bool)) Option[T]

Map executes the mapper function if value is present or returns None if absent.

func (Option[T]) MapNone

func (o Option[T]) MapNone(mapper func() (T, bool)) Option[T]

MapNone executes the mapper function if value is absent or returns Option. Play: https://go.dev/play/p/_KaHWZ6Q17b

func (Option[T]) Match

func (o Option[T]) Match(onValue func(value T) (T, bool), onNone func() (T, bool)) Option[T]

Match executes the first function if value is present and second function if absent. It returns a new Option.

func (Option[T]) MustGet

func (o Option[T]) MustGet() T

MustGet returns value if present or panics instead. Play: https://go.dev/play/p/RVBckjdi5WR

func (Option[T]) None

func (o Option[T]) None() bool

None returns false when value is present.

func (Option[T]) OrElse

func (o Option[T]) OrElse(fallback T) T

OrElse returns value if present or default value.

func (Option[T]) OrEmpty

func (o Option[T]) OrEmpty() T

OrEmpty returns value if present or empty value.

func (Option[T]) Some

func (o Option[T]) Some() bool

Some returns false when value is absent.

func (Option[T]) ToPointer

func (o Option[T]) ToPointer() *T

ToPointer returns value if present or a nil pointer. Play: https://go.dev/play/p/N43w92SM-Bs

type Result

type Result[T any] struct {
	// contains filtered or unexported fields
}

Result represents a result of an action having one of the following output: success or failure. An instance of Result is an instance of either Ok or Err.

func Err

func Err[T any](err error) Result[T]

Err builds a Result when value is invalid.

func Errf

func Errf[T any](format string, a ...any) Result[T]

Errf builds a Result when value is invalid. Errf formats according to a format specifier and returns the error as a value that satisfies Result[T].

func Ok

func Ok[T any](value T) Result[T]

Ok builds a Result when value is valid.

func Try

func Try[T any](f func() (T, error)) Result[T]

Try returns either a Ok or Err object.

func TupleToResult

func TupleToResult[T any](value T, err error) Result[T]

TupleToResult convert a pair of T and error into a Result. Play: https://go.dev/play/p/KWjfqQDHQwa

func (Result[T]) Error

func (r Result[T]) Error() error

Error returns error when value is invalid or nil.

func (Result[T]) FlatMap

func (r Result[T]) FlatMap(mapper func(value T) Result[T]) Result[T]

FlatMap executes the mapper function if Result is valid. It returns a new Result.

func (Result[T]) ForEach

func (r Result[T]) ForEach(mapper func(value T))

ForEach executes the given side-effecting function if Result is valid.

func (Result[T]) Get

func (r Result[T]) Get() (T, error)

Get returns value and error.

func (Result[T]) Map

func (r Result[T]) Map(mapper func(value T) (T, error)) Result[T]

Map executes the mapper function if Result is valid. It returns a new Result.

func (Result[T]) MapErr

func (r Result[T]) MapErr(mapper func(error) (T, error)) Result[T]

MapErr executes the mapper function if Result is invalid. It returns a new Result.

func (Result[T]) Match

func (r Result[T]) Match(onSuccess func(value T) (T, error), onError func(err error) (T, error)) Result[T]

Match executes the first function if Result is valid and second function if invalid. It returns a new Result.

func (Result[T]) MustGet

func (r Result[T]) MustGet() T

MustGet returns value when Result is valid or panics.

func (Result[T]) Ok

func (r Result[T]) Ok() bool

Ok returns true when value is valid.

func (Result[T]) OrElse

func (r Result[T]) OrElse(fallback T) T

OrElse returns value when Result is valid or default value.

func (Result[T]) OrEmpty

func (r Result[T]) OrEmpty() T

OrEmpty returns value when Result is valid or empty value.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL