reader

package
v2.2.50 Latest Latest
Warning

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

Go to latest
Published: Mar 8, 2026 License: Apache-2.0 Imports: 2 Imported by: 0

Documentation

Overview

Package reader provides a specialization of the Reader monad for context.Context.

This package offers a context-aware Reader monad that simplifies working with Go's context.Context in a functional programming style. It eliminates the need to explicitly thread context through function calls while maintaining type safety and composability.

Core Concept

The Reader monad represents computations that depend on a shared environment. In this package, that environment is fixed to context.Context, making it particularly useful for:

  • Request-scoped data propagation
  • Cancellation and timeout handling
  • Dependency injection via context values
  • Avoiding explicit context parameter threading

Type Definitions

  • Reader[A]: A computation that depends on context.Context and produces A
  • Kleisli[A, B]: A function from A to Reader[B] for composing computations
  • Operator[A, B]: A transformation from Reader[A] to Reader[B]

Usage Pattern

Instead of passing context explicitly through every function:

func processUser(ctx context.Context, userID string) (User, error) {
    user := fetchUser(ctx, userID)
    profile := fetchProfile(ctx, user.ProfileID)
    return enrichUser(ctx, user, profile), nil
}

You can use Reader to compose context-dependent operations:

fetchUser := func(userID string) Reader[User] {
    return func(ctx context.Context) User {
        // Use ctx for database access, cancellation, etc.
        return queryDatabase(ctx, userID)
    }
}

processUser := func(userID string) Reader[User] {
    return F.Pipe2(
        fetchUser(userID),
        reader.Chain(func(user User) Reader[Profile] {
            return fetchProfile(user.ProfileID)
        }),
        reader.Map(func(profile Profile) User {
            return enrichUser(user, profile)
        }),
    )
}

// Execute with context
ctx := context.Background()
user := processUser("user123")(ctx)

Integration with Standard Library

This package works seamlessly with Go's standard context package:

  • Context cancellation and deadlines are preserved
  • Context values can be accessed within Reader computations
  • Readers can be composed with context-aware libraries

Relationship to Other Packages

This package is a specialization of github.com/IBM/fp-go/v2/reader where the environment type R is fixed to context.Context. For more general Reader operations, see the base reader package.

For combining Reader with other monads:

Example: HTTP Request Handler

type RequestContext struct {
    UserID    string
    RequestID string
}

// Extract request context from context.Context
getRequestContext := func(ctx context.Context) RequestContext {
    return RequestContext{
        UserID:    ctx.Value("userID").(string),
        RequestID: ctx.Value("requestID").(string),
    }
}

// A Reader that logs with request context
logInfo := func(message string) Reader[function.Void] {
    return func(ctx context.Context) function.Void {
        reqCtx := getRequestContext(ctx)
        log.Printf("[%s] User %s: %s", reqCtx.RequestID, reqCtx.UserID, message)
        return function.VOID
    }
}

// Compose operations
handleRequest := func(data string) Reader[Response] {
    return F.Pipe2(
        logInfo("Processing request"),
        reader.Chain(func(_ function.Void) Reader[Result] {
            return processData(data)
        }),
        reader.Map(func(result Result) Response {
            return Response{Data: result}
        }),
    )
}

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Kleisli

type Kleisli[A, B any] = R.Reader[A, Reader[B]]

Kleisli represents a Kleisli arrow for the context-based Reader monad.

It's a function from A to Reader[B], used for composing Reader computations that all depend on the same context.Context.

Type Parameters:

  • A: The input type
  • B: The output type wrapped in Reader

Kleisli[A, B] is equivalent to func(A) func(context.Context) B

Kleisli arrows are fundamental for monadic composition, allowing you to chain operations that depend on context without explicitly passing the context through each function call.

Example:

// A Kleisli arrow that creates a greeting Reader from a name
greet := func(name string) Reader[string] {
    return func(ctx context.Context) string {
        if deadline, ok := ctx.Deadline(); ok {
            return fmt.Sprintf("Hello %s (deadline: %v)", name, deadline)
        }
        return fmt.Sprintf("Hello %s", name)
    }
}

// Use the Kleisli arrow
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
greeting := greet("Alice")(ctx) // "Hello Alice (deadline: ...)"

type Operator

type Operator[A, B any] = Kleisli[Reader[A], B]

Operator represents a transformation from one Reader to another.

It takes a Reader[A] and produces a Reader[B], where both readers depend on the same context.Context. This type is commonly used for operations like Map, Chain, and other transformations that convert readers while preserving the context dependency.

Type Parameters:

  • A: The input Reader's result type
  • B: The output Reader's result type

Operator[A, B] is equivalent to func(Reader[A]) func(context.Context) B

Operators enable building pipelines of context-dependent computations where each step can transform the result of the previous computation while maintaining access to the shared context.

Example:

// An operator that transforms int readers to string readers
intToString := func(r Reader[int]) Reader[string] {
    return func(ctx context.Context) string {
        value := r(ctx)
        return strconv.Itoa(value)
    }
}

// A Reader that extracts a timeout value from context
getTimeout := func(ctx context.Context) int {
    if deadline, ok := ctx.Deadline(); ok {
        return int(time.Until(deadline).Seconds())
    }
    return 0
}

// Transform the Reader
getTimeoutStr := intToString(getTimeout)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
result := getTimeoutStr(ctx) // "30" (approximately)

type Reader

type Reader[A any] = R.Reader[context.Context, A]

Reader represents a computation that depends on a context.Context and produces a value of type A.

This is a specialization of the generic Reader monad where the environment type is fixed to context.Context. This is particularly useful for Go applications that need to thread context through computations for cancellation, deadlines, and request-scoped values.

Type Parameters:

  • A: The result type produced by the computation

Reader[A] is equivalent to func(context.Context) A

The Reader monad enables:

  • Dependency injection using context values
  • Cancellation and timeout handling
  • Request-scoped data propagation
  • Avoiding explicit context parameter threading

Example:

// A Reader that extracts a user ID from context
getUserID := func(ctx context.Context) string {
    if userID, ok := ctx.Value("userID").(string); ok {
        return userID
    }
    return "anonymous"
}

// A Reader that checks if context is cancelled
isCancelled := func(ctx context.Context) bool {
    select {
    case <-ctx.Done():
        return true
    default:
        return false
    }
}

// Use the readers with a context
ctx := context.WithValue(context.Background(), "userID", "user123")
userID := getUserID(ctx)      // "user123"
cancelled := isCancelled(ctx) // false

Jump to

Keyboard shortcuts

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