fp-go

command module
v2.0.4 Latest Latest
Warning

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

Go to latest
Published: Dec 22, 2025 License: Apache-2.0 Imports: 4 Imported by: 0

README ΒΆ

fp-go V2: Enhanced Functional Programming for Go 1.24+

Go Reference Coverage Status Go Report Card

fp-go is a comprehensive functional programming library for Go, bringing type-safe functional patterns inspired by fp-ts to the Go ecosystem. Version 2 leverages generic type aliases introduced in Go 1.24, providing a more ergonomic and streamlined API.

πŸ“š Table of Contents

🎯 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

  • Go 1.24 or later (for generic type alias support)

πŸ“¦ Installation

go get github.com/IBM/fp-go/v2

πŸš€ Quick Start

Working with Option
package main

import (
    "fmt"
    "github.com/IBM/fp-go/v2/option"
    N "github.com/IBM/fp-go/v2/number"
)

func main() {
    // Create an Option
    some := option.Some(42)
    none := option.None[int]()
    
    // Map over values
    doubled := option.Map(N.Mul(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
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
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! <<<
}

⚠️ Breaking Changes

From V1 to V2
1. Generic Type Aliases

V2 uses generic type aliases which require Go 1.24+. This is the most significant change and enables cleaner type definitions.

V1:

type ReaderIOEither[R, E, A any] RD.Reader[R, IOE.IOEither[E, A]]

V2:

type ReaderIOEither[R, E, A any] = RD.Reader[R, IOE.IOEither[E, A]]
2. Generic Type Parameter Ordering

Type parameters that cannot be inferred from function arguments now come first, improving type inference.

V1:

// Ap in V1 - less intuitive ordering
func Ap[R, E, A, B any](fa ReaderIOEither[R, E, A]) func(ReaderIOEither[R, E, func(A) B]) ReaderIOEither[R, E, B]

V2:

// Ap in V2 - B comes first as it cannot be inferred
func Ap[B, R, E, A any](fa ReaderIOEither[R, E, A]) func(ReaderIOEither[R, E, func(A) B]) ReaderIOEither[R, E, B]

This change allows the Go compiler to infer more types automatically, reducing the need for explicit type parameters.

3. Pair Monad Semantics

Monadic operations for Pair now operate on the second argument to align with the Haskell definition.

V1:

// Operations on first element
pair := MakePair(1, "hello")
result := Map(N.Mul(2))(pair) // Pair(2, "hello")

V2:

// Operations on second element (Haskell-compatible)
pair := MakePair(1, "hello")
result := Map(func(s string) string { return s + "!" })(pair) // Pair(1, "hello!")
4. Endomorphism Compose Semantics

The Compose function for endomorphisms now follows mathematical function composition (right-to-left execution), aligning with standard functional programming conventions.

V1:

// Compose executed left-to-right
double := N.Mul(2)
increment := N.Add(1)
composed := Compose(double, increment)
result := composed(5) // (5 * 2) + 1 = 11

V2:

// Compose executes RIGHT-TO-LEFT (mathematical composition)
double := N.Mul(2)
increment := N.Add(1)
composed := Compose(double, increment)
result := composed(5) // (5 + 1) * 2 = 12

// Use MonadChain for LEFT-TO-RIGHT execution
chained := MonadChain(double, increment)
result2 := chained(5) // (5 * 2) + 1 = 11

Key Difference:

  • Compose(f, g) now means f ∘ g, which applies g first, then f (right-to-left)
  • MonadChain(f, g) applies f first, then g (left-to-right)

✨ Key Improvements

1. Simplified Type Declarations

Generic type aliases eliminate the need for namespace imports in type declarations.

V1 Approach:

import (
    ET "github.com/IBM/fp-go/either"
    OPT "github.com/IBM/fp-go/option"
)

func processData(input string) ET.Either[error, OPT.Option[int]] {
    // implementation
}

V2 Approach:

import (
    "github.com/IBM/fp-go/v2/result"
    "github.com/IBM/fp-go/v2/option"
)

// Define type aliases once
type Result[A any] = result.Result[A]
type Option[A any] = option.Option[A]

// Use them throughout your codebase
func processData(input string) Result[Option[int]] {
    // implementation
}
2. No More generic Subpackages

The library implementation no longer requires separate generic subpackages, making the codebase simpler and easier to understand.

V1 Structure:

either/
  either.go
  generic/
    either.go  // Generic implementation

V2 Structure:

either/
  either.go  // Single, clean implementation
3. Better Type Inference

The reordered type parameters allow the Go compiler to infer more types automatically:

V1:

// Often need explicit type parameters
result := Map[Context, error, int, string](transform)(value)

V2:

// Compiler can infer more types
result := Map(transform)(value)  // Cleaner!

πŸš€ Migration Guide

Step 1: Update Go Version

Ensure you're using Go 1.24 or later:

go version  # Should show go1.24 or higher
Step 2: Update Import Paths

Change all import paths from github.com/IBM/fp-go to github.com/IBM/fp-go/v2:

Before:

import (
    "github.com/IBM/fp-go/either"
    "github.com/IBM/fp-go/option"
)

After:

import (
    "github.com/IBM/fp-go/v2/either"
    "github.com/IBM/fp-go/v2/option"
)
Step 3: Remove generic Subpackage Imports

If you were using generic subpackages, remove them:

Before:

import (
    E "github.com/IBM/fp-go/either/generic"
)

After:

import (
    "github.com/IBM/fp-go/v2/either"
)
Step 4: Update Type Parameter Order

Review functions like Ap where type parameter order has changed. The compiler will help identify these:

Before:

result := Ap[Context, error, int, string](value)(funcInContext)

After:

result := Ap[string, Context, error, int](value)(funcInContext)
// Or better yet, let the compiler infer:
result := Ap(value)(funcInContext)
Step 5: Update Pair Operations

If you're using Pair, update operations to work on the second element:

Before (V1):

pair := MakePair(42, "data")
// Map operates on first element
result := Map(N.Mul(2))(pair)

After (V2):

pair := MakePair(42, "data")
// Map operates on second element
result := Map(func(s string) string { return s + "!" })(pair)
Step 6: Simplify Type Aliases

Create project-wide type aliases for common patterns:

// types.go - Define once, use everywhere
package myapp

import (
    "github.com/IBM/fp-go/v2/result"
    "github.com/IBM/fp-go/v2/option"
    "github.com/IBM/fp-go/v2/ioresult"
)

type Result[A any] = result.Result[A]
type Option[A any] = option.Option[A]
type IOResult[A any] = ioresult.IOResult[A]

πŸ†• What's New

Cleaner API Surface

The elimination of generic subpackages means:

  • Fewer imports to manage
  • Simpler package structure
  • Easier to navigate documentation
  • More intuitive API
Example: Before and After

V1 Complex Example:

import (
    ET "github.com/IBM/fp-go/either"
    EG "github.com/IBM/fp-go/either/generic"
    IOET "github.com/IBM/fp-go/ioeither"
    IOEG "github.com/IBM/fp-go/ioeither/generic"
)

func process() IOET.IOEither[error, string] {
    return IOEG.Map[error, int, string](
        strconv.Itoa,
    )(fetchData())
}

V2 Simplified Example:

import (
    "strconv"
    "github.com/IBM/fp-go/v2/ioresult"
)

type IOResult[A any] = ioresult.IOResult[A]

func process() IOResult[string] {
    return ioresult.Map(
        strconv.Itoa,
    )(fetchData())
}

πŸ“š Documentation

Core Modules
Standard Packages (Struct-based)
  • Option - Represent optional values without nil
  • Either - Type-safe error handling with left/right values
  • Result - Simplified Either with error as left type (recommended for error handling)
  • IO - Lazy evaluation and side effect management
  • IOResult - Combine IO with Result for error handling (recommended over IOEither)
  • Reader - Dependency injection pattern
  • ReaderIOResult - Combine Reader, IO, and Result for complex workflows
  • Array - Functional array operations
  • Record - Functional record/map operations
  • Optics - Lens, Prism, Optional, and Traversal for immutable updates
Idiomatic Packages (Tuple-based, High Performance)
  • idiomatic/option - Option monad using native Go (value, bool) tuples
  • idiomatic/result - Result monad using native Go (value, error) tuples
  • idiomatic/ioresult - IOResult monad using func() (value, error) for IO operations
  • idiomatic/readerresult - Reader monad combined with Result pattern
  • idiomatic/readerioresult - Reader monad combined with IOResult pattern

The idiomatic packages offer 2-10x performance improvements and zero allocations by using Go's native tuple patterns instead of struct wrappers. Use them for performance-critical code or when you prefer Go's native error handling style.

πŸ€” Should I Migrate?

Migrate to V2 if:

  • βœ… You can use Go 1.24+
  • βœ… You want cleaner, more maintainable code
  • βœ… You want better type inference
  • βœ… You're starting a new project

Stay on V1 if:

  • ⚠️ You're locked to Go < 1.24
  • ⚠️ Migration effort outweighs benefits for your project
  • ⚠️ 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

Found a bug or have a suggestion? Please open an issue on GitHub.

πŸ“„ License

This project is licensed under the Apache License 2.0. See the LICENSE file for details.


Made with ❀️ by IBM

Documentation ΒΆ

Overview ΒΆ

Package main contains the entry point for the code generator

Directories ΒΆ

Path Synopsis
Package array provides functional programming utilities for working with Go slices.
Package array provides functional programming utilities for working with Go slices.
Package assert provides functional assertion helpers for testing.
Package assert provides functional assertion helpers for testing.
Package boolean provides functional programming utilities for working with boolean values.
Package boolean provides functional programming utilities for working with boolean values.
Package bounded provides types and functions for working with bounded ordered types.
Package bounded provides types and functions for working with bounded ordered types.
Package bytes provides functional programming utilities for working with byte slices.
Package bytes provides functional programming utilities for working with byte slices.
cli
Package consumer provides types and utilities for functions that consume values without returning results.
Package consumer provides types and utilities for functions that consume values without returning results.
Package context contains versions of reader IO monads that work with a golang context.Context
Package context contains versions of reader IO monads that work with a golang context.Context
readerioresult
package readerioresult provides a specialized version of [readerioeither.ReaderIOResult] that uses context.Context as the context type and [error] as the left (error) type.
package readerioresult provides a specialized version of [readerioeither.ReaderIOResult] that uses context.Context as the context type and [error] as the left (error) type.
readerioresult/http
Package http provides functional HTTP client utilities built on top of ReaderIOResult monad.
Package http provides functional HTTP client utilities built on top of ReaderIOResult monad.
readerioresult/http/builder
Package builder provides utilities for building HTTP requests in a functional way using the ReaderIOResult monad.
Package builder provides utilities for building HTTP requests in a functional way using the ReaderIOResult monad.
readerresult
Package readerresult provides logging utilities for the ReaderResult monad, which combines the Reader monad (for dependency injection via context.Context) with the Result monad (for error handling).
Package readerresult provides logging utilities for the ReaderResult monad, which combines the Reader monad (for dependency injection via context.Context) with the Result monad (for error handling).
readerresult/exec
package readerresult implements a specialization of the Reader monad assuming a golang context as the context of the monad and a standard golang error
package readerresult implements a specialization of the Reader monad assuming a golang context as the context of the monad and a standard golang error
statereaderioresult
Package statereaderioresult provides a functional programming abstraction that combines four powerful concepts: State, Reader, IO, and Result monads, specialized for Go's context.Context.
Package statereaderioresult provides a functional programming abstraction that combines four powerful concepts: State, Reader, IO, and Result monads, specialized for Go's context.Context.
di
Package di implements functions and data types supporting dependency injection patterns.
Package di implements functions and data types supporting dependency injection patterns.
Package either provides the Either monad, a data structure representing a value of one of two possible types.
Package either provides the Either monad, a data structure representing a value of one of two possible types.
exec
Package exec provides utilities for executing system commands with Either-based error handling.
Package exec provides utilities for executing system commands with Either-based error handling.
http
Package http provides utilities for creating HTTP requests with Either-based error handling.
Package http provides utilities for creating HTTP requests with Either-based error handling.
testing
Package testing provides utilities for testing Either monad laws.
Package testing provides utilities for testing Either monad laws.
Package endomorphism provides functional programming utilities for working with endomorphisms.
Package endomorphism provides functional programming utilities for working with endomorphisms.
eq
Package eq provides type-safe equality comparisons for any type in Go.
Package eq provides type-safe equality comparisons for any type in Go.
Package erasure provides utilities for type erasure and type-safe conversion between generic types and the any type.
Package erasure provides utilities for type erasure and type-safe conversion between generic types and the any type.
Package errors provides functional utilities for working with Go errors.
Package errors provides functional utilities for working with Go errors.
Package function provides functional programming utilities for function composition, transformation, and manipulation.
Package function provides functional programming utilities for function composition, transformation, and manipulation.
Package http provides functional programming utilities for working with HTTP requests and responses.
Package http provides functional programming utilities for working with HTTP requests and responses.
builder
Package builder provides a functional, immutable HTTP request builder with composable operations.
Package builder provides a functional, immutable HTTP request builder with composable operations.
headers
Package headers provides constants and utilities for working with HTTP headers in a functional programming style.
Package headers provides constants and utilities for working with HTTP headers in a functional programming style.
Package identity implements the Identity monad, the simplest possible monad.
Package identity implements the Identity monad, the simplest possible monad.
Package idiomatic provides functional programming constructs optimized for idiomatic Go.
Package idiomatic provides functional programming constructs optimized for idiomatic Go.
context/readerresult
Package readerresult provides a ReaderResult monad specialized for context.Context.
Package readerresult provides a ReaderResult monad specialized for context.Context.
ioresult
Package ioresult provides functional programming combinators for working with IO operations that can fail with errors, following Go's idiomatic (value, error) tuple pattern.
Package ioresult provides functional programming combinators for working with IO operations that can fail with errors, following Go's idiomatic (value, error) tuple pattern.
ioresult/exec
Package exec provides utilities for executing system commands with IOResult-based error handling.
Package exec provides utilities for executing system commands with IOResult-based error handling.
option
Package option implements the Option monad using idiomatic Go tuple signatures.
Package option implements the Option monad using idiomatic Go tuple signatures.
option/number
Package number provides Option-based utilities for number conversions.
Package number provides Option-based utilities for number conversions.
readerioresult
Package readerioresult provides a ReaderIOResult monad that combines Reader, IO, and Result monads.
Package readerioresult provides a ReaderIOResult monad that combines Reader, IO, and Result monads.
readerresult
Package readerresult provides a ReaderResult monad that combines the Reader and Result monads.
Package readerresult provides a ReaderResult monad that combines the Reader and Result monads.
result
Package result provides an idiomatic Go approach to error handling using the (value, error) tuple pattern.
Package result provides an idiomatic Go approach to error handling using the (value, error) tuple pattern.
result/exec
Package exec provides utilities for executing system commands with Either-based error handling.
Package exec provides utilities for executing system commands with Either-based error handling.
result/http
Package http provides utilities for creating HTTP requests with Either-based error handling.
Package http provides utilities for creating HTTP requests with Either-based error handling.
internal
applicative/testing
Package testing provides law-based testing utilities for applicatives.
Package testing provides law-based testing utilities for applicatives.
eq
monad/testing
Package testing provides law-based testing utilities for monads.
Package testing provides law-based testing utilities for monads.
io
Package io provides the IO monad, representing synchronous computations that cannot fail.
Package io provides the IO monad, representing synchronous computations that cannot fail.
Package ioeither provides the IOEither monad, combining IO effects with Either for error handling.
Package ioeither provides the IOEither monad, combining IO effects with Either for error handling.
generic
Code generated by go generate; DO NOT EDIT.
Code generated by go generate; DO NOT EDIT.
Package iooption provides the IOOption monad, combining IO effects with Option for optional values.
Package iooption provides the IOOption monad, combining IO effects with Option for optional values.
Package ioresult provides the IOResult monad, combining IO effects with Result for error handling.
Package ioresult provides the IOResult monad, combining IO effects with Result for error handling.
iterator
iter
Package iter provides functional programming utilities for Go 1.23+ iterators.
Package iter provides functional programming utilities for Go 1.23+ iterators.
stateless
Package stateless defines a stateless (pure) iterator, i.e.
Package stateless defines a stateless (pure) iterator, i.e.
Package json provides functional wrappers around Go's encoding/json package using Either for error handling.
Package json provides functional wrappers around Go's encoding/json package using Either for error handling.
Package lazy provides a functional programming abstraction for synchronous computations without side effects.
Package lazy provides a functional programming abstraction for synchronous computations without side effects.
Package logging provides utilities for creating logging callbacks from standard log.Logger instances.
Package logging provides utilities for creating logging callbacks from standard log.Logger instances.
Package magma provides the Magma algebraic structure.
Package magma provides the Magma algebraic structure.
Package monoid provides the Monoid algebraic structure.
Package monoid provides the Monoid algebraic structure.
Package number provides algebraic structures and utility functions for numeric types.
Package number provides algebraic structures and utility functions for numeric types.
Package optics provides functional optics for composable data access and manipulation.
Package optics provides functional optics for composable data access and manipulation.
iso
Package iso provides isomorphisms - bidirectional transformations between types without loss of information.
Package iso provides isomorphisms - bidirectional transformations between types without loss of information.
iso/lens
Package lens provides conversions from isomorphisms to lenses.
Package lens provides conversions from isomorphisms to lenses.
iso/option
Package option provides isomorphisms for working with Option types.
Package option provides isomorphisms for working with Option types.
lens
Package lens provides functional optics for zooming into and modifying nested data structures.
Package lens provides functional optics for zooming into and modifying nested data structures.
lens/iso
Package iso provides utilities for composing lenses with isomorphisms.
Package iso provides utilities for composing lenses with isomorphisms.
lens/option
Package option provides utilities for working with lenses that focus on optional values.
Package option provides utilities for working with lenses that focus on optional values.
optional
Package optional provides optional optics for focusing on values that may not exist.
Package optional provides optional optics for focusing on values that may not exist.
prism
Package prism provides prisms - optics for focusing on variants within sum types.
Package prism provides prisms - optics for focusing on variants within sum types.
traversal
Package traversal provides traversals - optics for focusing on multiple values simultaneously.
Package traversal provides traversals - optics for focusing on multiple values simultaneously.
Package option defines the Option data structure and its monadic operations.
Package option defines the Option data structure and its monadic operations.
number
Package number provides Option-based utilities for number conversions.
Package number provides Option-based utilities for number conversions.
Package ord provides the Ord type class for types that support total ordering.
Package ord provides the Ord type class for types that support total ordering.
Package pair provides a strongly-typed data structure for holding two values with functional operations.
Package pair provides a strongly-typed data structure for holding two values with functional operations.
Package predicate provides functional programming utilities for working with predicates.
Package predicate provides functional programming utilities for working with predicates.
Package reader provides the Reader monad implementation for functional programming in Go.
Package reader provides the Reader monad implementation for functional programming in Go.
generic
Package generic provides generic array operations for custom Reader types.
Package generic provides generic array operations for custom Reader types.
Package readerio provides the ReaderIO monad, which combines the Reader and IO monads.
Package readerio provides the ReaderIO monad, which combines the Reader and IO monads.
Package readerioeither provides a functional programming abstraction that combines three powerful concepts: Reader, IO, and Either monads.
Package readerioeither provides a functional programming abstraction that combines three powerful concepts: Reader, IO, and Either monads.
generic
Code generated by go generate; DO NOT EDIT.
Code generated by go generate; DO NOT EDIT.
package readerioresult provides a functional programming abstraction that combines three powerful concepts: Reader, IO, and Either monads.
package readerioresult provides a functional programming abstraction that combines three powerful concepts: Reader, IO, and Either monads.
Package readeroption provides a monad transformer that combines the Reader and Option monads.
Package readeroption provides a monad transformer that combines the Reader and Option monads.
Package readerresult provides a ReaderResult monad that combines the Reader and Result monads.
Package readerresult provides a ReaderResult monad that combines the Reader and Result monads.
Package record contains monadic operations for maps as well as a rich set of utility functions
Package record contains monadic operations for maps as well as a rich set of utility functions
Package result provides the Result monad, a specialized Either monad with error as the left type.
Package result provides the Result monad, a specialized Either monad with error as the left type.
exec
Package exec provides utilities for executing system commands with Either-based error handling.
Package exec provides utilities for executing system commands with Either-based error handling.
http
Package http provides utilities for creating HTTP requests with Either-based error handling.
Package http provides utilities for creating HTTP requests with Either-based error handling.
testing
Package testing provides utilities for testing Either monad laws.
Package testing provides utilities for testing Either monad laws.
Package retry provides functional retry policies and combinators for implementing retry logic with configurable backoff strategies.
Package retry provides functional retry policies and combinators for implementing retry logic with configurable backoff strategies.
generic
Package generic provides generic retry combinators that work with any monadic type.
Package generic provides generic retry combinators that work with any monadic type.
samples
mostly-adequate
Package mostlyadequate contains examples from the "Mostly Adequate Guide to Functional Programming" adapted to Go using fp-go.
Package mostlyadequate contains examples from the "Mostly Adequate Guide to Functional Programming" adapted to Go using fp-go.
Package semigroup provides implementations of the Semigroup algebraic structure.
Package semigroup provides implementations of the Semigroup algebraic structure.
ord
Package statereaderioeither provides a functional programming abstraction that combines four powerful concepts: State, Reader, IO, and Either monads.
Package statereaderioeither provides a functional programming abstraction that combines four powerful concepts: State, Reader, IO, and Either monads.
Package tailrec provides a trampoline implementation for tail-call optimization in Go.
Package tailrec provides a trampoline implementation for tail-call optimization in Go.
Package tuple provides type-safe heterogeneous tuple data structures and operations.
Package tuple provides type-safe heterogeneous tuple data structures and operations.

Jump to

Keyboard shortcuts

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