1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-11-23 22:14:53 +02:00

doc: improve doc

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
Dr. Carsten Leue
2025-11-12 11:08:18 +01:00
parent eb7fc9f77b
commit 23333ce52c
9 changed files with 179 additions and 47 deletions

View File

@@ -2,25 +2,152 @@
[![Go Reference](https://pkg.go.dev/badge/github.com/IBM/fp-go/v2.svg)](https://pkg.go.dev/github.com/IBM/fp-go/v2) [![Go Reference](https://pkg.go.dev/badge/github.com/IBM/fp-go/v2.svg)](https://pkg.go.dev/github.com/IBM/fp-go/v2)
[![Coverage Status](https://coveralls.io/repos/github/IBM/fp-go/badge.svg?branch=main&flag=v2)](https://coveralls.io/github/IBM/fp-go?branch=main) [![Coverage Status](https://coveralls.io/repos/github/IBM/fp-go/badge.svg?branch=main&flag=v2)](https://coveralls.io/github/IBM/fp-go?branch=main)
[![Go Report Card](https://goreportcard.com/badge/github.com/IBM/fp-go/v2)](https://goreportcard.com/report/github.com/IBM/fp-go/v2)
Version 2 of fp-go leverages [generic type aliases](https://github.com/golang/go/issues/46477) introduced in Go 1.24, providing a more ergonomic and streamlined API. **fp-go** is a comprehensive functional programming library for Go, bringing type-safe functional patterns inspired by [fp-ts](https://gcanti.github.io/fp-ts/) to the Go ecosystem. Version 2 leverages [generic type aliases](https://github.com/golang/go/issues/46477) introduced in Go 1.24, providing a more ergonomic and streamlined API.
## 📚 Table of Contents ## 📚 Table of Contents
- [Overview](#-overview)
- [Features](#-features)
- [Requirements](#-requirements) - [Requirements](#-requirements)
- [Breaking Changes](#-breaking-changes) - [Installation](#-installation)
- [Quick Start](#-quick-start)
- [Breaking Changes](#️-breaking-changes)
- [Key Improvements](#-key-improvements) - [Key Improvements](#-key-improvements)
- [Migration Guide](#-migration-guide) - [Migration Guide](#-migration-guide)
- [Installation](#-installation)
- [What's New](#-whats-new) - [What's New](#-whats-new)
- [Documentation](#-documentation)
- [Contributing](#-contributing)
- [License](#-license)
## 🎯 Overview
fp-go brings the power of functional programming to Go with:
- **Type-safe abstractions** - Monads, Functors, Applicatives, and more
- **Composable operations** - Build complex logic from simple, reusable functions
- **Error handling** - Elegant error management with `Either`, `Result`, and `IOEither`
- **Lazy evaluation** - Control when and how computations execute
- **Optics** - Powerful lens, prism, and traversal operations for immutable data manipulation
## ✨ Features
- 🔒 **Type Safety** - Leverage Go's generics for compile-time guarantees
- 🧩 **Composability** - Chain operations naturally with functional composition
- 📦 **Rich Type System** - `Option`, `Either`, `Result`, `IO`, `Reader`, and more
- 🎯 **Practical** - Designed for real-world Go applications
- 🚀 **Performance** - Zero-cost abstractions where possible
- 📖 **Well-documented** - Comprehensive API documentation and examples
- 🧪 **Battle-tested** - Extensive test coverage
## 🔧 Requirements ## 🔧 Requirements
- **Go 1.24 or later** (for generic type alias support) - **Go 1.24 or later** (for generic type alias support)
## ⚠️ Breaking Changes ## 📦 Installation
### 1. Generic Type Aliases ```bash
go get github.com/IBM/fp-go/v2
```
## 🚀 Quick Start
### Working with Option
```go
package main
import (
"fmt"
"github.com/IBM/fp-go/v2/option"
)
func main() {
// Create an Option
some := option.Some(42)
none := option.None[int]()
// Map over values
doubled := option.Map(func(x int) int { return x * 2 })(some)
fmt.Println(option.GetOrElse(0)(doubled)) // Output: 84
// Chain operations
result := option.Chain(func(x int) option.Option[string] {
if x > 0 {
return option.Some(fmt.Sprintf("Positive: %d", x))
}
return option.None[string]()
})(some)
fmt.Println(option.GetOrElse("No value")(result)) // Output: Positive: 42
}
```
### Error Handling with Result
```go
package main
import (
"errors"
"fmt"
"github.com/IBM/fp-go/v2/result"
)
func divide(a, b int) result.Result[int] {
if b == 0 {
return result.Error[int](errors.New("division by zero"))
}
return result.Ok(a / b)
}
func main() {
res := divide(10, 2)
// Pattern match on the result
result.Fold(
func(err error) { fmt.Println("Error:", err) },
func(val int) { fmt.Println("Result:", val) },
)(res)
// Output: Result: 5
// Or use GetOrElse for a default value
value := result.GetOrElse(0)(divide(10, 0))
fmt.Println("Value:", value) // Output: Value: 0
}
```
### Composing IO Operations
```go
package main
import (
"fmt"
"github.com/IBM/fp-go/v2/io"
)
func main() {
// Define pure IO operations
readInput := io.MakeIO(func() string {
return "Hello, fp-go!"
})
// Transform the result
uppercase := io.Map(func(s string) string {
return fmt.Sprintf(">>> %s <<<", s)
})(readInput)
// Execute the IO operation
result := uppercase()
fmt.Println(result) // Output: >>> Hello, fp-go! <<<
}
```
### From V1 to V2
#### 1. Generic Type Aliases
V2 uses [generic type aliases](https://github.com/golang/go/issues/46477) which require Go 1.24+. This is the most significant change and enables cleaner type definitions. V2 uses [generic type aliases](https://github.com/golang/go/issues/46477) which require Go 1.24+. This is the most significant change and enables cleaner type definitions.
@@ -34,7 +161,7 @@ type ReaderIOEither[R, E, A any] RD.Reader[R, IOE.IOEither[E, A]]
type ReaderIOEither[R, E, A any] = RD.Reader[R, IOE.IOEither[E, A]] type ReaderIOEither[R, E, A any] = RD.Reader[R, IOE.IOEither[E, A]]
``` ```
### 2. Generic Type Parameter Ordering #### 2. Generic Type Parameter Ordering
Type parameters that **cannot** be inferred from function arguments now come first, improving type inference. Type parameters that **cannot** be inferred from function arguments now come first, improving type inference.
@@ -52,7 +179,7 @@ func Ap[B, R, E, A any](fa ReaderIOEither[R, E, A]) func(ReaderIOEither[R, E, fu
This change allows the Go compiler to infer more types automatically, reducing the need for explicit type parameters. This change allows the Go compiler to infer more types automatically, reducing the need for explicit type parameters.
### 3. Pair Monad Semantics #### 3. Pair Monad Semantics
Monadic operations for `Pair` now operate on the **second argument** to align with the [Haskell definition](https://hackage.haskell.org/package/TypeCompose-0.9.14/docs/Data-Pair.html). Monadic operations for `Pair` now operate on the **second argument** to align with the [Haskell definition](https://hackage.haskell.org/package/TypeCompose-0.9.14/docs/Data-Pair.html).
@@ -91,16 +218,16 @@ func processData(input string) ET.Either[error, OPT.Option[int]] {
**V2 Approach:** **V2 Approach:**
```go ```go
import ( import (
"github.com/IBM/fp-go/v2/either" "github.com/IBM/fp-go/v2/result"
"github.com/IBM/fp-go/v2/option" "github.com/IBM/fp-go/v2/option"
) )
// Define type aliases once // Define type aliases once
type Either[A any] = either.Either[error, A] type Result[A any] = result.Result[A]
type Option[A any] = option.Option[A] type Option[A any] = option.Option[A]
// Use them throughout your codebase // Use them throughout your codebase
func processData(input string) Either[Option[int]] { func processData(input string) Result[Option[int]] {
// implementation // implementation
} }
``` ```
@@ -230,20 +357,14 @@ Create project-wide type aliases for common patterns:
package myapp package myapp
import ( import (
"github.com/IBM/fp-go/v2/either" "github.com/IBM/fp-go/v2/result"
"github.com/IBM/fp-go/v2/option" "github.com/IBM/fp-go/v2/option"
"github.com/IBM/fp-go/v2/ioeither" "github.com/IBM/fp-go/v2/ioresult"
) )
type Either[A any] = either.Either[error, A] type Result[A any] = result.Result[A]
type Option[A any] = option.Option[A] type Option[A any] = option.Option[A]
type IOEither[A any] = ioeither.IOEither[error, A] type IOResult[A any] = ioresult.IOResult[A]
```
## 📦 Installation
```bash
go get github.com/IBM/fp-go/v2
``` ```
## 🆕 What's New ## 🆕 What's New
@@ -277,25 +398,37 @@ func process() IOET.IOEither[error, string] {
**V2 Simplified Example:** **V2 Simplified Example:**
```go ```go
import ( import (
"github.com/IBM/fp-go/v2/either" "strconv"
"github.com/IBM/fp-go/v2/ioeither" "github.com/IBM/fp-go/v2/ioresult"
) )
type IOEither[A any] = ioeither.IOEither[error, A] type IOResult[A any] = ioresult.IOResult[A]
func process() IOEither[string] { func process() IOResult[string] {
return ioeither.Map( return ioresult.Map(
strconv.Itoa, strconv.Itoa,
)(fetchData()) )(fetchData())
} }
``` ```
## 📚 Additional Resources ## 📚 Documentation
- [Main README](../README.md) - Core concepts and design philosophy - **[API Documentation](https://pkg.go.dev/github.com/IBM/fp-go/v2)** - Complete API reference
- [API Documentation](https://pkg.go.dev/github.com/IBM/fp-go/v2) - **[Code Samples](./samples/)** - Practical examples and use cases
- [Code Samples](../samples/) - **[Go 1.24 Release Notes](https://tip.golang.org/doc/go1.24)** - Information about generic type aliases
- [Go 1.24 Release Notes](https://tip.golang.org/doc/go1.24)
### Core Modules
- **Option** - Represent optional values without nil
- **Either** - Type-safe error handling with left/right values
- **Result** - Simplified Either with error as left type
- **IO** - Lazy evaluation and side effect management
- **IOEither** - Combine IO with error handling
- **Reader** - Dependency injection pattern
- **ReaderIOEither** - Combine Reader, IO, and Either for complex workflows
- **Array** - Functional array operations
- **Record** - Functional record/map operations
- **Optics** - Lens, Prism, Optional, and Traversal for immutable updates
## 🤔 Should I Migrate? ## 🤔 Should I Migrate?
@@ -310,10 +443,25 @@ func process() IOEither[string] {
- Migration effort outweighs benefits for your project - Migration effort outweighs benefits for your project
- You need stability in production (V2 is newer) - You need stability in production (V2 is newer)
## 🤝 Contributing
Contributions are welcome! Here's how you can help:
1. **Report bugs** - Open an issue with a clear description and reproduction steps
2. **Suggest features** - Share your ideas for improvements
3. **Submit PRs** - Fix bugs or add features (please discuss major changes first)
4. **Improve docs** - Help make the documentation clearer and more comprehensive
Please read our contribution guidelines before submitting pull requests.
## 🐛 Issues and Feedback ## 🐛 Issues and Feedback
Found a bug or have a suggestion? Please [open an issue](https://github.com/IBM/fp-go/issues) on GitHub. Found a bug or have a suggestion? Please [open an issue](https://github.com/IBM/fp-go/issues) on GitHub.
## 📄 License ## 📄 License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details. This project is licensed under the Apache License 2.0. See the [LICENSE](https://github.com/IBM/fp-go/blob/main/LICENSE) file for details.
---
**Made with by IBM**

View File

@@ -883,5 +883,3 @@ func BenchmarkExecuteApPar_CanceledContext(b *testing.B) {
benchResult = rioe(ctx)() benchResult = rioe(ctx)()
} }
} }
// Made with Bob

View File

@@ -875,5 +875,3 @@ func TestBracket(t *testing.T) {
assert.Equal(t, E.Left[int](err), res) assert.Equal(t, E.Left[int](err), res)
}) })
} }
// Made with Bob

View File

@@ -648,5 +648,3 @@ func BenchmarkString_Left(b *testing.B) {
benchString = left.String() benchString = left.String()
} }
} }
// Made with Bob

View File

@@ -265,5 +265,3 @@
// In practice, they are the same type, but the lazy package provides a more focused // In practice, they are the same type, but the lazy package provides a more focused
// API for pure computations. // API for pure computations.
package lazy package lazy
// Made with Bob

View File

@@ -501,5 +501,3 @@ func TestMapComposition(t *testing.T) {
assert.Equal(t, 20, result()) assert.Equal(t, 20, result())
} }
// Made with Bob

View File

@@ -56,5 +56,3 @@ func TestApS(t *testing.T) {
assert.Equal(t, res(context.Background())(), result.Of("John Doe")) assert.Equal(t, res(context.Background())(), result.Of("John Doe"))
} }
// Made with Bob

View File

@@ -160,5 +160,3 @@ func TestUncurry3(t *testing.T) {
assert.True(t, ok) assert.True(t, ok)
assert.Equal(t, 42, result) assert.Equal(t, 42, result)
} }
// Made with Bob

View File

@@ -110,5 +110,3 @@ func TestFrom3(t *testing.T) {
result2 := roFunc("test", 5, false)(ctx1) result2 := roFunc("test", 5, false)(ctx1)
assert.Equal(t, O.None[string](), result2) assert.Equal(t, O.None[string](), result2)
} }
// Made with Bob