{"id":15036567,"url":"https://github.com/ibm/fp-go","last_synced_at":"2026-04-01T17:20:51.501Z","repository":{"id":182046452,"uuid":"662620190","full_name":"IBM/fp-go","owner":"IBM","description":"functional programming library for golang","archived":false,"fork":false,"pushed_at":"2026-01-31T13:07:32.000Z","size":15377,"stargazers_count":1928,"open_issues_count":3,"forks_count":67,"subscribers_count":17,"default_branch":"main","last_synced_at":"2026-01-31T23:04:38.840Z","etag":null,"topics":["functional-programming","go","golang","library","monad","utility"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/IBM.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-07-05T14:18:19.000Z","updated_at":"2026-01-31T15:59:12.000Z","dependencies_parsed_at":"2026-02-05T11:00:34.235Z","dependency_job_id":null,"html_url":"https://github.com/IBM/fp-go","commit_stats":{"total_commits":237,"total_committers":15,"mean_commits":15.8,"dds":"0.23628691983122363","last_synced_commit":"6a6d53f025d8fdf24c630deaad8b4d47be484a97"},"previous_names":["ibm/fp-go"],"tags_count":286,"template":false,"template_full_name":null,"purl":"pkg:github/IBM/fp-go","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IBM%2Ffp-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IBM%2Ffp-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IBM%2Ffp-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IBM%2Ffp-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/IBM","download_url":"https://codeload.github.com/IBM/fp-go/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IBM%2Ffp-go/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29120481,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-05T10:47:47.471Z","status":"ssl_error","status_checked_at":"2026-02-05T10:45:08.119Z","response_time":65,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["functional-programming","go","golang","library","monad","utility"],"created_at":"2024-09-24T20:31:34.918Z","updated_at":"2026-02-05T11:01:03.199Z","avatar_url":"https://github.com/IBM.png","language":"Go","readme":"# fp-go: Functional Programming Library for Go\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/IBM/fp-go.svg)](https://pkg.go.dev/github.com/IBM/fp-go)\n[![Coverage Status](https://coveralls.io/repos/github/IBM/fp-go/badge.svg?branch=main)](https://coveralls.io/github/IBM/fp-go?branch=main)\n\n**🚧 Work in progress! 🚧** Despite major version 1 (due to [semantic-release limitations](https://github.com/semantic-release/semantic-release/issues/1507)), we're working to minimize breaking changes.\n\n![logo](resources/images/logo.png)\n\nA comprehensive functional programming library for Go, strongly influenced by the excellent [fp-ts](https://github.com/gcanti/fp-ts) library for TypeScript.\n\n## 📚 Table of Contents\n\n- [Getting Started](#-getting-started)\n- [Design Goals](#-design-goals)\n- [Core Concepts](#-core-concepts)\n- [Comparison to Idiomatic Go](#comparison-to-idiomatic-go)\n- [Implementation Notes](#implementation-notes)\n- [Common Operations](#common-operations)\n- [Resources](#-resources)\n\n## 🚀 Getting Started\n\n### Installation\n\n```bash\ngo get github.com/IBM/fp-go\n```\n\n### Quick Example\n\n```go\nimport (\n    \"errors\"\n    \"github.com/IBM/fp-go/either\"\n    \"github.com/IBM/fp-go/function\"\n)\n\n// Pure function that can fail\nfunc divide(a, b int) either.Either[error, int] {\n    if b == 0 {\n        return either.Left[int](errors.New(\"division by zero\"))\n    }\n    return either.Right[error](a / b)\n}\n\n// Compose operations safely\nresult := function.Pipe2(\n    divide(10, 2),\n    either.Map(func(x int) int { return x * 2 }),\n    either.GetOrElse(func() int { return 0 }),\n)\n// result = 10\n```\n\n### Resources\n\n- 📖 [API Documentation](https://pkg.go.dev/github.com/IBM/fp-go)\n- 💡 [Code Samples](./samples/)\n- 🆕 [V2 Documentation](./v2/README.md) (requires Go 1.24+)\n\n## 🎯 Design Goals\n\nThis library aims to provide a set of data types and functions that make it easy and fun to write maintainable and testable code in Go. It encourages the following patterns:\n\n### Core Principles\n\n- **Pure Functions**: Write many small, testable, and pure functions that produce output only depending on their input and execute no side effects\n- **Side Effect Isolation**: Isolate side effects into lazily executed functions using the `IO` monad\n- **Consistent Composition**: Expose a consistent set of composition functions across all data types\n  - Each data type has a small set of composition functions\n  - Functions are named consistently across all data types\n  - Semantics of same-named functions are consistent across data types\n\n### 🧘🏽 Alignment with the Zen of Go\n\nThis library respects and aligns with [The Zen of Go](https://the-zen-of-go.netlify.app/):\n\n| Principle | Alignment | Explanation |\n|-----------|-----------|-------------|\n| 🧘🏽 Each package fulfills a single purpose | ✔️ | Each top-level package (Option, Either, ReaderIOEither, etc.) defines one data type and its operations |\n| 🧘🏽 Handle errors explicitly | ✔️ | Clear distinction between operations that can/cannot fail; failures represented via `Either` type |\n| 🧘🏽 Return early rather than nesting deeply | ✔️ | Small, focused functions composed together; `Either` monad handles error paths automatically |\n| 🧘🏽 Leave concurrency to the caller | ✔️ | Pure functions are synchronous; I/O operations are asynchronous by default |\n| 🧘🏽 Before you launch a goroutine, know when it will stop | 🤷🏽 | Library doesn't start goroutines; Task monad supports cancellation via context |\n| 🧘🏽 Avoid package level state | ✔️ | No package-level state anywhere |\n| 🧘🏽 Simplicity matters | ✔️ | Small, consistent interface across data types; focus on business logic |\n| 🧘🏽 Write tests to lock in behaviour | 🟡 | Programming pattern encourages testing; library has growing test coverage |\n| 🧘🏽 If you think it's slow, first prove it with a benchmark | ✔️ | Performance claims should be backed by benchmarks |\n| 🧘🏽 Moderation is a virtue | ✔️ | No custom goroutines or expensive synchronization; atomic counters for coordination |\n| 🧘🏽 Maintainability counts | ✔️ | Small, concise operations; pure functions with clear type signatures |\n\n## 💡 Core Concepts\n\n### Data Types\n\nThe library provides several key functional data types:\n\n- **`Option[A]`**: Represents an optional value (Some or None)\n- **`Either[E, A]`**: Represents a value that can be one of two types (Left for errors, Right for success)\n- **`IO[A]`**: Represents a lazy computation that produces a value\n- **`IOEither[E, A]`**: Represents a lazy computation that can fail\n- **`Reader[R, A]`**: Represents a computation that depends on an environment\n- **`ReaderIOEither[R, E, A]`**: Combines Reader, IO, and Either for effectful computations with dependencies\n- **`Task[A]`**: Represents an asynchronous computation\n- **`State[S, A]`**: Represents a stateful computation\n\n### Monadic Operations\n\nAll data types support common monadic operations:\n\n- **`Map`**: Transform the value inside a context\n- **`Chain`** (FlatMap): Transform and flatten nested contexts\n- **`Ap`**: Apply a function in a context to a value in a context\n- **`Of`**: Wrap a value in a context\n- **`Fold`**: Extract a value from a context\n\n## Comparison to Idiomatic Go\n\nThis section explains how functional APIs differ from idiomatic Go and how to convert between them.\n\n### Pure Functions\n\nPure functions take input parameters and compute output without changing global state or mutating inputs. They always return the same output for the same input.\n\n#### Without Errors\n\nIf your pure function doesn't return an error, the idiomatic signature works as-is:\n\n```go\nfunc add(a, b int) int {\n    return a + b\n}\n```\n\n#### With Errors\n\n**Idiomatic Go:**\n```go\nfunc divide(a, b int) (int, error) {\n    if b == 0 {\n        return 0, errors.New(\"division by zero\")\n    }\n    return a / b, nil\n}\n```\n\n**Functional Style:**\n```go\nfunc divide(a, b int) either.Either[error, int] {\n    if b == 0 {\n        return either.Left[int](errors.New(\"division by zero\"))\n    }\n    return either.Right[error](a / b)\n}\n```\n\n**Conversion:**\n- Use `either.EitherizeXXX` to convert from idiomatic to functional style\n- Use `either.UneitherizeXXX` to convert from functional to idiomatic style\n\n### Effectful Functions\n\nAn effectful function changes data outside its scope or doesn't always produce the same output for the same input.\n\n#### Without Errors\n\n**Functional signature:** `IO[T]`\n\n```go\nfunc getCurrentTime() io.IO[time.Time] {\n    return func() time.Time {\n        return time.Now()\n    }\n}\n```\n\n#### With Errors\n\n**Functional signature:** `IOEither[error, T]`\n\n```go\nfunc readFile(path string) ioeither.IOEither[error, []byte] {\n    return func() either.Either[error, []byte] {\n        data, err := os.ReadFile(path)\n        if err != nil {\n            return either.Left[[]byte](err)\n        }\n        return either.Right[error](data)\n    }\n}\n```\n\n**Conversion:**\n- Use `ioeither.EitherizeXXX` to convert idiomatic Go functions to functional style\n\n### Go Context\n\nFunctions that take a `context.Context` are effectful because they depend on mutable context.\n\n**Idiomatic Go:**\n```go\nfunc fetchData(ctx context.Context, url string) ([]byte, error) {\n    // implementation\n}\n```\n\n**Functional Style:**\n```go\nfunc fetchData(url string) readerioeither.ReaderIOEither[context.Context, error, []byte] {\n    return func(ctx context.Context) ioeither.IOEither[error, []byte] {\n        return func() either.Either[error, []byte] {\n            // implementation\n        }\n    }\n}\n```\n\n**Conversion:**\n- Use `readerioeither.EitherizeXXX` to convert idiomatic Go functions with context to functional style\n\n## Implementation Notes\n\n### Generics\n\nAll monadic operations use Go generics for type safety:\n\n- ✅ **Pros**: Type-safe composition, IDE support, compile-time correctness\n- ⚠️ **Cons**: May result in larger binaries (different versions per type)\n- 💡 **Tip**: For binary size concerns, use type erasure with `any` type\n\n### Ordering of Generic Type Parameters\n\nGo requires all type parameters on the global function definition. Parameters that cannot be auto-detected come first:\n\n```go\n// Map: B cannot be auto-detected, so it comes first\nfunc Map[R, E, A, B any](f func(A) B) func(ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]\n\n// Ap: B cannot be auto-detected from the argument\nfunc Ap[B, R, E, A any](fa ReaderIOEither[R, E, A]) func(ReaderIOEither[R, E, func(A) B]) ReaderIOEither[R, E, B]\n```\n\nThis ordering maximizes type inference where possible.\n\n### Use of the ~ Operator\n\nGo doesn't support generic type aliases (until Go 1.24), only type definitions. The `~` operator allows generic implementations to work with compatible types:\n\n```go\ntype ReaderIOEither[R, E, A any] RD.Reader[R, IOE.IOEither[E, A]]\n```\n\n**Generic Subpackages:**\n- Each higher-level type has a `generic` subpackage with fully generic implementations\n- These are for library extensions, not end-users\n- Main packages specialize generic implementations for convenience\n\n### Higher Kinded Types (HKT)\n\nGo doesn't support HKT natively. This library addresses this by:\n\n- Introducing HKTs as individual types (e.g., `HKTA` for `HKT[A]`)\n- Implementing generic algorithms in the `internal` package\n- Keeping complexity hidden from end-users\n\n## Common Operations\n\n### Map/Chain/Ap/Flap\n\n| Operator | Parameter        | Monad           | Result   | Use Case |\n| -------- | ---------------- | --------------- | -------- | -------- |\n| Map      | `func(A) B`      | `HKT[A]`        | `HKT[B]` | Transform value in context |\n| Chain    | `func(A) HKT[B]` | `HKT[A]`        | `HKT[B]` | Transform and flatten |\n| Ap       | `HKT[A]`         | `HKT[func(A)B]` | `HKT[B]` | Apply function in context |\n| Flap     | `A`              | `HKT[func(A)B]` | `HKT[B]` | Apply value to function in context |\n\n### Example: Chaining Operations\n\n```go\nimport (\n    \"github.com/IBM/fp-go/either\"\n    \"github.com/IBM/fp-go/function\"\n)\n\nresult := function.Pipe3(\n    either.Right[error](10),\n    either.Map(func(x int) int { return x * 2 }),\n    either.Chain(func(x int) either.Either[error, int] {\n        if x \u003e 15 {\n            return either.Right[error](x)\n        }\n        return either.Left[int](errors.New(\"too small\"))\n    }),\n    either.GetOrElse(func() int { return 0 }),\n)\n```\n\n## 📚 Resources\n\n- [API Documentation](https://pkg.go.dev/github.com/IBM/fp-go)\n- [Code Samples](./samples/)\n- [V2 Documentation](./v2/README.md) - New features in Go 1.24+\n- [fp-ts](https://github.com/gcanti/fp-ts) - Original TypeScript inspiration\n\n## 🤝 Contributing\n\nContributions are welcome! Please feel free to submit issues or pull requests.\n\n## 📄 License\n\nThis project is licensed under the Apache License 2.0 - see the LICENSE file for details.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fibm%2Ffp-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fibm%2Ffp-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fibm%2Ffp-go/lists"}