Awesome
mo - Monads
🦄 samber/mo
brings monads and popular FP abstractions to Go projects. samber/mo
uses the recent Go 1.18+ Generics.
Inspired by:
- Scala
- Rust
- FP-TS
See also:
- samber/lo: A Lodash-style Go library based on Go 1.18+ Generics
- samber/do: A dependency injection toolkit based on Go 1.18+ Generics
Why this name?
I love short name for such utility library. This name is similar to "Monad Go" and no Go package uses this name.
💡 Features
We currently support the following data types:
Option[T]
(Maybe)Result[T]
Either[A, B]
EitherX[T1, ..., TX]
(With X between 3 and 5)Future[T]
IO[T]
IOEither[T]
Task[T]
TaskEither[T]
State[S, A]
🚀 Install
go get github.com/samber/mo@v1
This library is v1 and follows SemVer strictly.
No breaking changes will be made to exported APIs before v2.0.0.
This library has no dependencies except the Go std lib.
💡 Quick start
You can import mo
using:
import (
"github.com/samber/mo"
)
Then use one of the helpers below:
option1 := mo.Some(42)
// Some(42)
option1.
FlatMap(func (value int) Option[int] {
return Some(value*2)
}).
FlatMap(func (value int) Option[int] {
return Some(value%2)
}).
FlatMap(func (value int) Option[int] {
return Some(value+21)
}).
OrElse(1234)
// 21
option2 := mo.None[int]()
// None
option2.OrElse(1234)
// 1234
option3 := option1.Match(
func(i int) (int, bool) {
// when value is present
return i * 2, true
},
func() (int, bool) {
// when value is absent
return 0, false
},
)
// Some(42)
More examples in documentation.
Tips for lazy developers
I cannot recommend it, but in case you are too lazy for repeating mo.
everywhere, you can import the entire library into the namespace.
import (
. "github.com/samber/mo"
)
I take no responsibility on this junk. 😁 💩
🤠 Documentation and examples
GoDoc: https://godoc.org/github.com/samber/mo
Option[T any]
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
.
Implements:
mo.Foldable[T, U]
Constructors:
mo.Some()
doc - playmo.None()
doc - playmo.TupleToOption()
doc - playmo.EmptyableToOption()
doc - playmo.PointerToOption()
doc - play
Methods:
.IsPresent()
doc - play.IsAbsent()
doc - play.Size()
doc - play.Get()
doc - play.MustGet()
doc - play.OrElse()
doc - play.OrEmpty()
doc - play.ToPointer()
doc - play.ForEach()
doc.Match()
doc - play.Map()
doc - play.MapNone()
doc - play.FlatMap()
doc - play.MarshalJSON()
doc.UnmarshalJSON()
doc.MarshalText()
doc.UnmarshalText()
doc.MarshalBinary()
doc.UnmarshalBinary()
doc.GobEncode()
doc.GobDecode()
doc.Scan()
doc.Value()
doc
Other:
mo.Fold[T, U, R any](f Foldable[T, U], successFunc func(U) R, failureFunc func(T) R) R
doc
Result[T any]
Result
respresent 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
. It could be compared to Either[error, T]
.
Implements:
mo.Foldable[T, U]
Constructors:
mo.Ok()
doc - playmo.Err()
doc - playmo.Errf()
doc - playmo.TupleToResult()
doc - playmo.Try()
doc - play
Methods:
.IsOk()
doc - play.IsError()
doc - play.Error()
doc - play.Get()
doc - play.MustGet()
doc - play.OrElse()
doc - play.OrEmpty()
doc - play.ToEither()
doc - play.ForEach()
doc.Match()
doc - play.Map()
doc - play.MapErr()
doc - play.FlatMap()
doc - play
Other:
mo.Fold[T, U, R any](f Foldable[T, U], successFunc func(U) R, failureFunc func(T) R) R
docmo.Do[T any](fn func() T) (result mo.Result[T])
doc
Either[L any, R any]
Either
represents a value of 2 possible types. An instance of Either
is an instance of either A
or B
.
Implements:
mo.Foldable[T, U]
Constructors:
Methods:
.IsLeft()
doc.IsRight()
doc.Left()
doc.Right()
doc.MustLeft()
doc.MustRight()
doc.Unpack()
doc.LeftOrElse()
doc.RightOrElse()
doc.LeftOrEmpty()
doc.RightOrEmpty()
doc.Swap()
doc.ForEach()
doc.Match()
doc.MapLeft()
doc.MapRight()
doc
Other:
mo.Fold[T, U, R any](f Foldable[T, U], successFunc func(U) R, failureFunc func(T) R) R
doc
EitherX[T1, ..., TX] (With X between 3 and 5)
EitherX
respresents a value of X possible types. For example, an Either3
value is either T1
, T2
or T3
.
Constructors:
mo.NewEitherXArgY()
doc. Eg:mo.NewEither3Arg1[A, B, C](A)
mo.NewEither3Arg2[A, B, C](B)
mo.NewEither3Arg3[A, B, C](C)
mo.NewEither4Arg1[A, B, C, D](A)
mo.NewEither4Arg2[A, B, C, D](B)
- ...
Methods:
.IsArgX()
doc.ArgX()
doc.MustArgX()
doc.Unpack()
doc.ArgXOrElse()
doc.ArgXOrEmpty()
doc.ForEach()
doc.Match()
doc.MapArgX()
doc
Future[T any]
Future
represents a value which may or may not currently be available, but will be available at some point, or an exception if that value could not be made available.
Constructors:
mo.NewFuture()
doc
Methods:
IO[T any]
IO
represents a non-deterministic synchronous computation that can cause side effects, yields a value of type R
and never fails.
Constructors:
Methods:
.Run()
doc
IOEither[T any]
IO
represents a non-deterministic synchronous computation that can cause side effects, yields a value of type R
and can fail.
Constructors:
mo.NewIOEither()
docmo.NewIOEither1()
docmo.NewIOEither2()
docmo.NewIOEither3()
docmo.NewIOEither4()
docmo.NewIOEither5()
doc
Methods:
.Run()
doc
Task[T any]
Task
represents a non-deterministic asynchronous computation that can cause side effects, yields a value of type R
and never fails.
Constructors:
mo.NewTask()
docmo.NewTask1()
docmo.NewTask2()
docmo.NewTask3()
docmo.NewTask4()
docmo.NewTask5()
docmo.NewTaskFromIO()
docmo.NewTaskFromIO1()
docmo.NewTaskFromIO2()
docmo.NewTaskFromIO3()
docmo.NewTaskFromIO4()
docmo.NewTaskFromIO5()
doc
Methods:
.Run()
doc
TaskEither[T any]
TaskEither
represents a non-deterministic asynchronous computation that can cause side effects, yields a value of type R
and can fail.
Constructors:
Methods:
State[S any, A any]
State
represents a function (S) -> (A, S)
, where S
is state, A
is result.
Constructors:
Methods:
Foldable[T, U]
Foldable represents a type that can be folded into a single value based on its state.
mo.Fold[T, U, R any](f Foldable[T, U], successFunc func(U) R, failureFunc func(T) R) R
doc
🛩 Benchmark
// @TODO
This library does not use reflect
package. We don't expect overhead.
🤝 Contributing
- Ping me on Twitter @samuelberthe (DMs, mentions, whatever :))
- Fork the project
- Fix open issues or request new features
Don't hesitate ;)
With Docker
docker-compose run --rm dev
Without Docker
# Install some dev dependencies
make tools
# Run tests
make test
# or
make watch-test
👤 Contributors
💫 Show your support
Give a ⭐️ if this project helped you!
📝 License
Copyright © 2022 Samuel Berthe.
This project is MIT licensed.