statereaderioresult

package
v2.2.21 Latest Latest
Warning

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

Go to latest
Published: Feb 24, 2026 License: Apache-2.0 Imports: 22 Imported by: 0

Documentation

Overview

Package statereaderioresult provides a functional programming abstraction that combines four powerful concepts: State, Reader, IO, and Result monads, specialized for Go's context.Context.

StateReaderIOResult

StateReaderIOResult[S, A] represents a computation that:

  • Manages state of type S (State)
  • Depends on a context.Context (Reader)
  • Performs side effects (IO)
  • Can fail with an [error] or succeed with a value of type A (Result)

This is a specialization of StateReaderIOEither with:

This is particularly useful for:

  • Stateful computations with dependency injection using Go contexts
  • Error handling in effectful computations with state
  • Composing operations that need access to context, manage state, and can fail
  • Working with Go's standard context patterns (cancellation, deadlines, values)

Core Operations

Construction:

  • Of/Right: Create a successful computation with a value
  • Left: Create a failed computation with an error
  • FromState: Lift a State into StateReaderIOResult
  • FromIO: Lift an IO into StateReaderIOResult
  • FromResult: Lift a Result into StateReaderIOResult
  • FromIOResult: Lift an IOResult into StateReaderIOResult
  • FromReaderIOResult: Lift a ReaderIOResult into StateReaderIOResult

Transformation:

  • Map: Transform the success value
  • Chain: Sequence dependent computations (monadic bind)
  • Flatten: Flatten nested StateReaderIOResult

Combination:

  • Ap: Apply a function in a context to a value in a context

Context Access:

  • Asks: Get a value derived from the context
  • Local: Run a computation with a modified context

Kleisli Arrows:

  • FromResultK: Lift a Result-returning function to a Kleisli arrow
  • FromIOK: Lift an IO-returning function to a Kleisli arrow
  • FromIOResultK: Lift an IOResult-returning function to a Kleisli arrow
  • FromReaderIOResultK: Lift a ReaderIOResult-returning function to a Kleisli arrow
  • ChainResultK: Chain with a Result-returning function
  • ChainIOResultK: Chain with an IOResult-returning function
  • ChainReaderIOResultK: Chain with a ReaderIOResult-returning function

Do Notation (Monadic Composition):

  • Do: Start a do-notation chain
  • Bind: Bind a value from a computation
  • BindTo: Bind a value to a simple constructor
  • Let: Compute a derived value
  • LetTo: Set a constant value
  • ApS: Apply in sequence (for applicative composition)
  • BindL/ApSL/LetL/LetToL: Lens-based variants for working with nested structures

Example Usage

type AppState struct {
    RequestCount int
    LastError    error
}

// A computation that manages state, depends on context, performs IO, and can fail
func processRequest(data string) statereaderioresult.StateReaderIOResult[AppState, string] {
    return func(state AppState) readerioresult.ReaderIOResult[pair.Pair[AppState, string]] {
        return func(ctx context.Context) ioresult.IOResult[pair.Pair[AppState, string]] {
            return func() result.Result[pair.Pair[AppState, string]] {
                // Check context for cancellation
                if ctx.Err() != nil {
                    return result.Error[pair.Pair[AppState, string]](ctx.Err())
                }
                // Update state
                newState := AppState{RequestCount: state.RequestCount + 1}
                // Perform IO operations
                return result.Of(pair.MakePair(newState, "processed: " + data))
            }
        }
    }
}

// Compose operations using do-notation
result := function.Pipe3(
    statereaderioresult.Do[AppState](State{}),
    statereaderioresult.Bind(
        func(result string) func(State) State { return func(s State) State { return State{result: result} } },
        func(s State) statereaderioresult.StateReaderIOResult[AppState, string] {
            return processRequest(s.input)
        },
    ),
    statereaderioresult.Map[AppState](func(s State) string { return s.result }),
)

// Execute with initial state and context
initialState := AppState{RequestCount: 0}
ctx := t.Context()
outcome := result(initialState)(ctx)() // Returns result.Result[pair.Pair[AppState, string]]

Context Integration

This package is designed to work seamlessly with Go's context.Context:

// Using context values
getUserID := statereaderioresult.Asks[AppState, string](func(ctx context.Context) statereaderioresult.StateReaderIOResult[AppState, string] {
    userID, ok := ctx.Value("userID").(string)
    if !ok {
        return statereaderioresult.Left[AppState, string](errors.New("missing userID"))
    }
    return statereaderioresult.Of[AppState](userID)
})

// Using context cancellation
withTimeout := statereaderioresult.Local[AppState, string](func(ctx context.Context) context.Context {
    ctx, _ = context.WithTimeout(ctx, 5*time.Second)
    return ctx
})

Monad Laws

StateReaderIOResult satisfies the monad laws:

  • Left Identity: Of(a) >>= f ≡ f(a)
  • Right Identity: m >>= Of ≡ m
  • Associativity: (m >>= f) >>= g ≡ m >>= (x => f(x) >>= g)

These laws are verified in the testing subpackage.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Applicative

func Applicative[
	S, A, B any,
]() applicative.Applicative[A, B, StateReaderIOResult[S, A], StateReaderIOResult[S, B], StateReaderIOResult[S, func(A) B]]

Applicative implements the applicative.Applicative operations for StateReaderIOResult

func Eq

func Eq[S, A any](eqr eq.Eq[ReaderIOResult[Pair[S, A]]]) func(S) eq.Eq[StateReaderIOResult[S, A]]

Eq implements the equals predicate for values contained in the StateReaderIOResult monad

func FromStrictEquals

func FromStrictEquals[S comparable, A comparable]() func(context.Context) func(S) eq.Eq[StateReaderIOResult[S, A]]

FromStrictEquals constructs an eq.Eq from the canonical comparison function

func Functor

func Functor[
	S, A, B any,
]() functor.Functor[A, B, StateReaderIOResult[S, A], StateReaderIOResult[S, B]]

Functor implements the functor.Functor operations for StateReaderIOResult

func Local

func Local[S, A any](f func(context.Context) context.Context) func(StateReaderIOResult[S, A]) StateReaderIOResult[S, A]

Local runs a computation with a modified context. The function f transforms the context before passing it to the computation.

Example:

// Modify context before running computation
withTimeout := statereaderioresult.Local[AppState](
    func(ctx context.Context) context.Context {
        ctx, _ = context.WithTimeout(ctx, 60*time.Second)
        return ctx
    }
)
result := withTimeout(computation)

func Monad

func Monad[
	S, A, B any,
]() monad.Monad[A, B, StateReaderIOResult[S, A], StateReaderIOResult[S, B], StateReaderIOResult[S, func(A) B]]

Monad implements the monad.Monad operations for StateReaderIOResult

func Pointed

func Pointed[
	S, A any,
]() pointed.Pointed[A, StateReaderIOResult[S, A]]

Pointed implements the pointed.Pointed operations for StateReaderIOResult

Types

type Endomorphism

type Endomorphism[A any] = endomorphism.Endomorphism[A]

Endomorphism represents a function from A to A.

func ApSL

func ApSL[ST, S, T any](
	lens Lens[S, T],
	fa StateReaderIOResult[ST, T],
) Endomorphism[StateReaderIOResult[ST, S]]

ApSL is a lens-based variant of ApS for working with nested structures. It uses a lens to focus on a specific field in the state.

func BindL

func BindL[ST, S, T any](
	lens Lens[S, T],
	f Kleisli[ST, T, T],
) Endomorphism[StateReaderIOResult[ST, S]]

BindL is a lens-based variant of Bind for working with nested structures. It uses a lens to focus on a specific field in the state.

func LetL

func LetL[ST, S, T any](
	lens Lens[S, T],
	f Endomorphism[T],
) Endomorphism[StateReaderIOResult[ST, S]]

LetL is a lens-based variant of Let for working with nested structures. It uses a lens to focus on a specific field in the state.

func LetToL

func LetToL[ST, S, T any](
	lens Lens[S, T],
	b T,
) Endomorphism[StateReaderIOResult[ST, S]]

LetToL is a lens-based variant of LetTo for working with nested structures. It uses a lens to focus on a specific field in the state.

type IO

type IO[A any] = io.IO[A]

IO represents a computation that performs side effects and produces a value of type A.

type IOResult

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

IOResult represents a computation that performs side effects and can fail with an error or succeed with a value A.

type Kleisli

type Kleisli[S, A, B any] = Reader[A, StateReaderIOResult[S, B]]

Kleisli represents a Kleisli arrow - a function that takes a value A and returns a StateReaderIOResult computation producing B. This is used for monadic composition via Chain.

func FromIOK

func FromIOK[S, A, B any](f func(A) IO[B]) Kleisli[S, A, B]

FromIOK lifts an IO-returning function into a Kleisli arrow for StateReaderIOResult.

func FromIOResultK

func FromIOResultK[S, A, B any](f func(A) IOResult[B]) Kleisli[S, A, B]

FromIOResultK lifts an IOResult-returning function into a Kleisli arrow for StateReaderIOResult.

func FromReaderIOResultK

func FromReaderIOResultK[S, A, B any](f func(A) ReaderIOResult[B]) Kleisli[S, A, B]

FromReaderIOResultK lifts a ReaderIOResult-returning function into a Kleisli arrow for StateReaderIOResult.

func FromResultK

func FromResultK[S, A, B any](f func(A) Result[B]) Kleisli[S, A, B]

FromResultK lifts a Result-returning function into a Kleisli arrow for StateReaderIOResult.

Example:

validate := func(x int) result.Result[int] {
    if x > 0 { return result.Of(x) }
    return result.Error[int](errors.New("negative"))
}
kleisli := statereaderioresult.FromResultK[AppState](validate)

func WithResource

func WithResource[A, S, RES, ANY any](
	onCreate StateReaderIOResult[S, RES],
	onRelease Kleisli[S, RES, ANY],
) Kleisli[S, Kleisli[S, RES, A], A]

WithResource constructs a function that creates a resource with state management, operates on it, and then releases the resource. This ensures proper resource cleanup even in the presence of errors, following the Resource Acquisition Is Initialization (RAII) pattern.

The state is threaded through all operations: resource creation, usage, and release.

The resource lifecycle with state management is:

  1. onCreate: Acquires the resource (may modify state)
  2. use: Operates on the resource with current state (provided as argument to the returned function)
  3. onRelease: Releases the resource with current state (called regardless of success or failure)

Type parameters:

  • A: The type of the result produced by using the resource
  • S: The state type that is threaded through all operations
  • RES: The resource type
  • ANY: The type returned by the release function (typically ignored)

Parameters:

  • onCreate: A stateful computation that acquires the resource
  • onRelease: A stateful function that releases the resource, called with the resource and current state, executed regardless of errors

Returns:

A function that takes a resource-using function and returns a StateReaderIOResult that manages
the resource lifecycle with state

Example:

type AppState struct {
    openFiles int
}

// Resource creation that updates state
openFile := func(filename string) StateReaderIOResult[AppState, *File] {
    return func(state AppState) ReaderIOResult[Pair[AppState, *File]] {
        return func(ctx context.Context) IOResult[Pair[AppState, *File]] {
            return func() Result[Pair[AppState, *File]] {
                file, err := os.Open(filename)
                if err != nil {
                    return result.Error[Pair[AppState, *File]](err)
                }
                newState := AppState{openFiles: state.openFiles + 1}
                return result.Of(pair.MakePair(newState, file))
            }
        }
    }
}

// Resource release that updates state
closeFile := func(f *File) StateReaderIOResult[AppState, int] {
    return func(state AppState) ReaderIOResult[Pair[AppState, int]] {
        return func(ctx context.Context) IOResult[Pair[AppState, int]] {
            return func() Result[Pair[AppState, int]] {
                f.Close()
                newState := AppState{openFiles: state.openFiles - 1}
                return result.Of(pair.MakePair(newState, 0))
            }
        }
    }
}

// Use the resource with automatic cleanup
withFile := WithResource(
    openFile("data.txt"),
    closeFile,
)

result := withFile(func(f *File) StateReaderIOResult[AppState, string] {
    return readContent(f) // File will be closed automatically
})

// Execute the computation
initialState := AppState{openFiles: 0}
ctx := t.Context()
outcome := result(initialState)(ctx)()

type Lens

type Lens[S, A any] = lens.Lens[S, A]

Lens is an optic that focuses on a field of type A within a structure of type S.

type Operator

type Operator[S, A, B any] = Reader[StateReaderIOResult[S, A], StateReaderIOResult[S, B]]

Operator represents a function that transforms one StateReaderIOResult into another. This is commonly used for building composable operations via Map, Chain, etc.

func Ap

func Ap[B, S, A any](fa StateReaderIOResult[S, A]) Operator[S, func(A) B, B]

Ap is the curried version of MonadAp. Returns a function that applies a wrapped function to the given wrapped value.

func ApS

func ApS[ST, S1, S2, T any](
	setter func(T) func(S1) S2,
	fa StateReaderIOResult[ST, T],
) Operator[ST, S1, S2]

ApS applies a computation in sequence and binds the result to a field. This is the applicative version of Bind.

func Bind

func Bind[ST, S1, S2, T any](
	setter func(T) func(S1) S2,
	f Kleisli[ST, S1, T],
) Operator[ST, S1, S2]

Bind executes a computation and binds its result to a field in the accumulator state. This is used in do-notation to sequence dependent computations.

Example:

result := function.Pipe2(
    statereaderioresult.Do[AppState](State{}),
    statereaderioresult.Bind(
        func(name string) func(State) State {
            return func(s State) State { return State{name: name, age: s.age} }
        },
        func(s State) statereaderioresult.StateReaderIOResult[AppState, string] {
            return statereaderioresult.Of[AppState]("John")
        },
    ),
)

func BindTo

func BindTo[ST, S1, T any](
	setter func(T) S1,
) Operator[ST, T, S1]

BindTo wraps a value in a simple constructor, typically used to start a do-notation chain after getting an initial value.

Example:

result := function.Pipe2(
    statereaderioresult.Of[AppState](42),
    statereaderioresult.BindTo[AppState](func(x int) State { return State{value: x} }),
)

func Chain

func Chain[S, A, B any](f Kleisli[S, A, B]) Operator[S, A, B]

Chain is the curried version of MonadChain. Returns a function that sequences computations.

Example:

stringify := statereaderioresult.Chain[AppState](func(x int) statereaderioresult.StateReaderIOResult[AppState, string] {
    return statereaderioresult.Of[AppState](fmt.Sprintf("%d", x))
})
result := function.Pipe1(statereaderioresult.Of[AppState](42), stringify)

func ChainIOResultK

func ChainIOResultK[S, A, B any](f func(A) IOResult[B]) Operator[S, A, B]

ChainIOResultK is the curried version of MonadChainIOResultK.

func ChainReaderIOResultK

func ChainReaderIOResultK[S, A, B any](f func(A) ReaderIOResult[B]) Operator[S, A, B]

ChainReaderIOResultK is the curried version of MonadChainReaderIOResultK.

func ChainResultK

func ChainResultK[S, A, B any](f func(A) Result[B]) Operator[S, A, B]

ChainResultK is the curried version of MonadChainResultK.

func FilterOrElse added in v2.1.0

func FilterOrElse[S, A any](pred Predicate[A], onFalse func(A) error) Operator[S, A, A]

FilterOrElse filters a StateReaderIOResult value based on a predicate. This is a convenience wrapper around statereaderioeither.FilterOrElse that fixes the context type to context.Context and the error type to error.

If the predicate returns true for the Right value, it passes through unchanged. If the predicate returns false, it transforms the Right value into a Left (error) using onFalse. Left values are passed through unchanged.

Parameters:

  • pred: A predicate function that tests the Right value
  • onFalse: A function that converts the failing value into an error

Returns:

  • An Operator that filters StateReaderIOResult values based on the predicate

Example:

type AppState struct {
    Counter int
}

// Validate that a number is positive
isPositive := N.MoreThan(0)
onNegative := func(n int) error { return fmt.Errorf("%d is not positive", n) }

filter := statereaderioresult.FilterOrElse[AppState](isPositive, onNegative)
result := filter(statereaderioresult.Right[AppState](42))(AppState{})(t.Context())()

func Let

func Let[ST, S1, S2, T any](
	key func(T) func(S1) S2,
	f func(S1) T,
) Operator[ST, S1, S2]

Let computes a derived value and binds it to a field in the accumulator state. Unlike Bind, this does not execute a monadic computation, just a pure function.

Example:

result := function.Pipe2(
    statereaderioresult.Do[AppState](State{age: 25}),
    statereaderioresult.Let(
        func(isAdult bool) func(State) State {
            return func(s State) State { return State{age: s.age, isAdult: isAdult} }
        },
        func(s State) bool { return s.age >= 18 },
    ),
)

func LetTo

func LetTo[ST, S1, S2, T any](
	key func(T) func(S1) S2,
	b T,
) Operator[ST, S1, S2]

LetTo binds a constant value to a field in the accumulator state.

Example:

result := function.Pipe2(
    statereaderioresult.Do[AppState](State{}),
    statereaderioresult.LetTo(
        func(status string) func(State) State {
            return func(s State) State { return State{...s, status: status} }
        },
        "active",
    ),
)

func Map

func Map[S, A, B any](f func(A) B) Operator[S, A, B]

Map is the curried version of MonadMap. Returns a function that transforms a StateReaderIOResult.

Example:

double := statereaderioresult.Map[AppState](N.Mul(2))
result := function.Pipe1(statereaderioresult.Of[AppState](21), double)

type Pair

type Pair[L, R any] = pair.Pair[L, R]

Pair represents a tuple of two values.

type Predicate added in v2.1.0

type Predicate[A any] = predicate.Predicate[A]

type Reader

type Reader[R, A any] = reader.Reader[R, A]

Reader represents a computation that depends on an environment/context of type R and produces a value of type A.

type ReaderIOResult

type ReaderIOResult[A any] = RIORES.ReaderIOResult[A]

ReaderIOResult represents a computation that depends on a context.Context, performs side effects, and can fail with an error or succeed with a value A.

type Result

type Result[A any] = result.Result[A]

Result represents a value that can be either an error or a success value. This is specialized to use [error] as the error type.

type State

type State[S, A any] = state.State[S, A]

State represents a stateful computation that takes an initial state S and returns a pair of the new state S and a value A.

type StateReaderIOResult

type StateReaderIOResult[S, A any] = Reader[S, ReaderIOResult[Pair[S, A]]]

StateReaderIOResult represents a stateful computation that:

  • Takes an initial state S
  • Depends on a context.Context
  • Performs side effects (IO)
  • Can fail with an [error] or succeed with a value A
  • Returns a pair of the new state S and the result

This is the main type of this package, combining State, Reader, IO, and Result monads. It is a specialization of StateReaderIOEither with:

func Asks

func Asks[S, A any](f func(context.Context) StateReaderIOResult[S, A]) StateReaderIOResult[S, A]

Asks creates a computation that derives a value from the context. The function receives the context and returns a StateReaderIOResult.

Example:

getValue := statereaderioresult.Asks[AppState, string](
    func(ctx context.Context) statereaderioresult.StateReaderIOResult[AppState, string] {
        return statereaderioresult.Of[AppState](ctx.Value("key").(string))
    },
)

func Do

func Do[ST, A any](
	empty A,
) StateReaderIOResult[ST, A]

Do starts a do-notation chain for building computations in a fluent style. This is typically used with Bind, Let, and other combinators to compose stateful, context-dependent computations that can fail.

Example:

type State struct {
    name string
    age  int
}
result := function.Pipe2(
    statereaderioresult.Do[AppState](State{}),
    statereaderioresult.Bind(...),
    statereaderioresult.Let(...),
)

func FromIO

func FromIO[S, A any](fa IO[A]) StateReaderIOResult[S, A]

FromIO lifts an IO computation into a StateReaderIOResult. The state is passed through unchanged and the context is ignored.

func FromIOResult

func FromIOResult[S, A any](fa IOResult[A]) StateReaderIOResult[S, A]

FromIOResult lifts an IOResult into a StateReaderIOResult. The state is passed through unchanged and the context is ignored.

func FromReaderIOResult

func FromReaderIOResult[S, A any](fa ReaderIOResult[A]) StateReaderIOResult[S, A]

FromReaderIOResult lifts a ReaderIOResult into a StateReaderIOResult. The state is passed through unchanged.

Example:

riores := readerioresult.Of(42)
result := statereaderioresult.FromReaderIOResult[AppState](riores)

func FromResult

func FromResult[S, A any](ma Result[A]) StateReaderIOResult[S, A]

FromResult lifts a Result into a StateReaderIOResult. The state is passed through unchanged and the context is ignored.

Example:

result := statereaderioresult.FromResult[AppState](result.Of(42))

func FromState

func FromState[S, A any](sa State[S, A]) StateReaderIOResult[S, A]

FromState lifts a State computation into a StateReaderIOResult. The computation cannot fail (uses the error type).

func Left

func Left[S, A any](e error) StateReaderIOResult[S, A]

Left creates a StateReaderIOResult that represents a failed computation with the given error. The error value is immediately available and does not depend on state or context.

Example:

result := statereaderioresult.Left[AppState, string](errors.New("validation failed"))
// Returns a failed computation that ignores state and context

func MonadAp

func MonadAp[B, S, A any](fab StateReaderIOResult[S, func(A) B], fa StateReaderIOResult[S, A]) StateReaderIOResult[S, B]

MonadAp applies a function wrapped in a StateReaderIOResult to a value wrapped in a StateReaderIOResult. If either the function or the value fails, the error is propagated. The state is threaded through both computations sequentially. This is the applicative apply operation.

Example:

fab := statereaderioresult.Of[AppState](N.Mul(2))
fa := statereaderioresult.Of[AppState](21)
result := statereaderioresult.MonadAp(fab, fa) // Result contains 42

func MonadChain

func MonadChain[S, A, B any](fa StateReaderIOResult[S, A], f Kleisli[S, A, B]) StateReaderIOResult[S, B]

MonadChain sequences two computations, passing the result of the first to a function that produces the second computation. This is the monadic bind operation. The state is threaded through both computations.

Example:

result := statereaderioresult.MonadChain(
    statereaderioresult.Of[AppState](5),
    func(x int) statereaderioresult.StateReaderIOResult[AppState, string] {
        return statereaderioresult.Of[AppState](fmt.Sprintf("value: %d", x))
    },
)

func MonadChainIOResultK

func MonadChainIOResultK[S, A, B any](ma StateReaderIOResult[S, A], f func(A) IOResult[B]) StateReaderIOResult[S, B]

MonadChainIOResultK chains a StateReaderIOResult with an IOResult-returning function.

func MonadChainReaderIOResultK

func MonadChainReaderIOResultK[S, A, B any](ma StateReaderIOResult[S, A], f func(A) ReaderIOResult[B]) StateReaderIOResult[S, B]

MonadChainReaderIOResultK chains a StateReaderIOResult with a ReaderIOResult-returning function.

func MonadChainResultK

func MonadChainResultK[S, A, B any](ma StateReaderIOResult[S, A], f func(A) Result[B]) StateReaderIOResult[S, B]

MonadChainResultK chains a StateReaderIOResult with a Result-returning function.

func MonadMap

func MonadMap[S, A, B any](fa StateReaderIOResult[S, A], f func(A) B) StateReaderIOResult[S, B]

MonadMap transforms the success value of a StateReaderIOResult using the provided function. If the computation fails, the error is propagated unchanged. The state is threaded through the computation. This is the functor map operation.

Example:

result := statereaderioresult.MonadMap(
    statereaderioresult.Of[AppState](21),
    N.Mul(2),
) // Result contains 42

func Of

func Of[S, A any](a A) StateReaderIOResult[S, A]

Of creates a StateReaderIOResult that represents a successful computation with the given value. This is the monadic return/pure operation for StateReaderIOResult. Equivalent to Right.

Example:

result := statereaderioresult.Of[AppState](42)
// Returns a successful computation containing 42
func Right[S, A any](a A) StateReaderIOResult[S, A]

Right creates a StateReaderIOResult that represents a successful computation with the given value. The value is wrapped and the state is passed through unchanged.

Example:

result := statereaderioresult.Right[AppState](42)
// Returns a successful computation containing 42

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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