$npx -y skills add samber/cc-skills-golang --skill golang-samber-moMonadic types for Golang using samber/mo — Option, Result, Either, Future, IO, Task, and State types for type-safe nullable values, error handling, and functional composition with pipeline sub-packages. Apply when using or adopting samber/mo, when the codebase imports `github.com
| 1 | **Persona:** You are a Go engineer bringing functional programming safety to Go. You use monads to make impossible states unrepresentable — nil checks become type constraints, error handling becomes composable pipelines. |
| 2 | |
| 3 | **Thinking mode:** Use `ultrathink` when designing multi-step Option/Result/Either pipelines. Wrong type choice creates unnecessary wrapping/unwrapping that defeats the purpose of monads. |
| 4 | |
| 5 | # samber/mo — Monads and Functional Abstractions for Go |
| 6 | |
| 7 | Go 1.18+ library providing type-safe monadic types with zero dependencies. Inspired by Scala, Rust, and fp-ts. |
| 8 | |
| 9 | **Official Resources:** |
| 10 | |
| 11 | - [pkg.go.dev/github.com/samber/mo](https://pkg.go.dev/github.com/samber/mo) |
| 12 | - [github.com/samber/mo](https://github.com/samber/mo) |
| 13 | |
| 14 | This skill is not exhaustive. Please refer to library documentation and code examples for more information. For Go package docs, symbols, versions, importers, and known vulnerabilities, → See `samber/cc-skills-golang@golang-pkg-go-dev` skill (`godig`) — prefer it over Context7 for Go package facts. To navigate this library's usage in your own code (definitions, call sites, diagnostics), → See `samber/cc-skills-golang@golang-gopls` skill (`gopls`). Context7 remains a fallback for docs not indexed on pkg.go.dev. |
| 15 | |
| 16 | ```bash |
| 17 | go get github.com/samber/mo |
| 18 | ``` |
| 19 | |
| 20 | For an introduction to functional programming concepts and why monads are valuable in Go, see [Monads Guide](./references/monads-guide.md). |
| 21 | |
| 22 | ## Core Types at a Glance |
| 23 | |
| 24 | | Type | Purpose | Think of it as... | |
| 25 | | --- | --- | --- | |
| 26 | | `Option[T]` | Value that may be absent | Rust's `Option`, Java's `Optional` | |
| 27 | | `Result[T]` | Operation that may fail | Rust's `Result<T, E>`, replaces `(T, error)` | |
| 28 | | `Either[L, R]` | Value of one of two types | Scala's `Either`, TypeScript discriminated union | |
| 29 | | `EitherX[L, R]` | Value of one of X types | Scala's `Either`, TypeScript discriminated union | |
| 30 | | `Future[T]` | Async value not yet available | JavaScript `Promise` | |
| 31 | | `IO[T]` | Lazy synchronous side effect | Haskell's `IO` | |
| 32 | | `Task[T]` | Lazy async computation | fp-ts `Task` | |
| 33 | | `State[S, A]` | Stateful computation | Haskell's `State` monad | |
| 34 | |
| 35 | ## Option[T] — Nullable Values Without nil |
| 36 | |
| 37 | Represents a value that is either present (`Some`) or absent (`None`). Eliminates nil pointer risks at the type level. |
| 38 | |
| 39 | ```go |
| 40 | import "github.com/samber/mo" |
| 41 | |
| 42 | name := mo.Some("Alice") // Option[string] with value |
| 43 | empty := mo.None[string]() // Option[string] without value |
| 44 | fromPtr := mo.PointerToOption(ptr) // nil pointer -> None |
| 45 | |
| 46 | // Safe extraction |
| 47 | name.OrElse("Anonymous") // "Alice" |
| 48 | empty.OrElse("Anonymous") // "Anonymous" |
| 49 | |
| 50 | // Transform if present, skip if absent |
| 51 | upper := name.Map(func(s string) (string, bool) { |
| 52 | return strings.ToUpper(s), true |
| 53 | }) |
| 54 | ``` |
| 55 | |
| 56 | **Key methods:** `Some`, `None`, `Get`, `MustGet`, `OrElse`, `OrEmpty`, `Map`, `FlatMap`, `Match`, `ForEach`, `ToPointer`, `IsPresent`, `IsAbsent`. |
| 57 | |
| 58 | Option implements `json.Marshaler/Unmarshaler`, `sql.Scanner`, `driver.Valuer` — use it directly in JSON structs and database models. |
| 59 | |
| 60 | For full API reference, see [Option Reference](./references/option.md). |
| 61 | |
| 62 | ## Result[T] — Error Handling as Values |
| 63 | |
| 64 | Represents success (`Ok`) or failure (`Err`). Equivalent to `Either[error, T]` but specialized for Go's error pattern. |
| 65 | |
| 66 | ```go |
| 67 | // Wrap Go's (value, error) pattern |
| 68 | result := mo.TupleToResult(os.ReadFile("config.yaml")) |
| 69 | |
| 70 | // Same-type transform — errors short-circuit automatically |
| 71 | upper := mo.Ok("hello").Map(func(s string) (string, error) { |
| 72 | return strings.ToUpper(s), nil |
| 73 | }) |
| 74 | // Ok("HELLO") |
| 75 | |
| 76 | // Extract with fallback |
| 77 | val := upper.OrElse("default") |
| 78 | ``` |
| 79 | |
| 80 | **Go limitation:** Direct methods (`.Map`, `.FlatMap`) cannot change the type parameter — `Result[T].Map` returns `Result[T]`, not `Result[U]`. Go methods cannot introduce new type parameters. For type-changing transforms (e.g. `Result[[]byte]` to `Result[Config]`), use sub-package functions or `mo.Do`: |
| 81 | |
| 82 | ```go |
| 83 | import "github.com/samber/mo/result" |
| 84 | |
| 85 | // Type-changing pipeline: []byte |