2025-11-06 09:27:00 +01:00
|
|
|
// Copyright (c) 2024 - 2025 IBM Corp.
|
|
|
|
|
// All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
|
|
package statereaderioeither
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"github.com/IBM/fp-go/v2/either"
|
|
|
|
|
"github.com/IBM/fp-go/v2/function"
|
|
|
|
|
"github.com/IBM/fp-go/v2/internal/statet"
|
2025-11-18 10:58:24 +01:00
|
|
|
"github.com/IBM/fp-go/v2/ioeither"
|
2025-11-06 09:27:00 +01:00
|
|
|
"github.com/IBM/fp-go/v2/readerioeither"
|
|
|
|
|
)
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// Left creates a StateReaderIOEither 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 := statereaderioeither.Left[AppState, Config, string](errors.New("validation failed"))
|
|
|
|
|
// // Returns a failed computation that ignores state and context
|
2025-11-06 09:27:00 +01:00
|
|
|
func Left[S, R, A, E any](e E) StateReaderIOEither[S, R, E, A] {
|
|
|
|
|
return function.Constant1[S](readerioeither.Left[R, Pair[S, A]](e))
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// Right creates a StateReaderIOEither that represents a successful computation with the given value.
|
|
|
|
|
// The value is wrapped and the state is passed through unchanged.
|
|
|
|
|
//
|
|
|
|
|
// Example:
|
|
|
|
|
//
|
|
|
|
|
// result := statereaderioeither.Right[AppState, Config, error](42)
|
|
|
|
|
// // Returns a successful computation containing 42
|
2025-11-06 09:27:00 +01:00
|
|
|
func Right[S, R, E, A any](a A) StateReaderIOEither[S, R, E, A] {
|
|
|
|
|
return statet.Of[StateReaderIOEither[S, R, E, A]](readerioeither.Of[R, E, Pair[S, A]], a)
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// Of creates a StateReaderIOEither that represents a successful computation with the given value.
|
|
|
|
|
// This is the monadic return/pure operation for StateReaderIOEither.
|
|
|
|
|
// Equivalent to [Right].
|
|
|
|
|
//
|
|
|
|
|
// Example:
|
|
|
|
|
//
|
|
|
|
|
// result := statereaderioeither.Of[AppState, Config, error](42)
|
|
|
|
|
// // Returns a successful computation containing 42
|
2025-11-06 09:27:00 +01:00
|
|
|
func Of[S, R, E, A any](a A) StateReaderIOEither[S, R, E, A] {
|
|
|
|
|
return Right[S, R, E](a)
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// MonadMap transforms the success value of a StateReaderIOEither 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 := statereaderioeither.MonadMap(
|
|
|
|
|
// statereaderioeither.Of[AppState, Config, error](21),
|
|
|
|
|
// func(x int) int { return x * 2 },
|
|
|
|
|
// ) // Result contains 42
|
2025-11-06 09:27:00 +01:00
|
|
|
func MonadMap[S, R, E, A, B any](fa StateReaderIOEither[S, R, E, A], f func(A) B) StateReaderIOEither[S, R, E, B] {
|
|
|
|
|
return statet.MonadMap[StateReaderIOEither[S, R, E, A], StateReaderIOEither[S, R, E, B]](
|
|
|
|
|
readerioeither.MonadMap[R, E, Pair[S, A], Pair[S, B]],
|
|
|
|
|
fa,
|
|
|
|
|
f,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// Map is the curried version of [MonadMap].
|
|
|
|
|
// Returns a function that transforms a StateReaderIOEither.
|
|
|
|
|
//
|
|
|
|
|
// Example:
|
|
|
|
|
//
|
|
|
|
|
// double := statereaderioeither.Map[AppState, Config, error](func(x int) int { return x * 2 })
|
|
|
|
|
// result := function.Pipe1(statereaderioeither.Of[AppState, Config, error](21), double)
|
2025-11-06 09:27:00 +01:00
|
|
|
func Map[S, R, E, A, B any](f func(A) B) Operator[S, R, E, A, B] {
|
|
|
|
|
return statet.Map[StateReaderIOEither[S, R, E, A], StateReaderIOEither[S, R, E, B]](
|
|
|
|
|
readerioeither.Map[R, E, Pair[S, A], Pair[S, B]],
|
|
|
|
|
f,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// 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 := statereaderioeither.MonadChain(
|
|
|
|
|
// statereaderioeither.Of[AppState, Config, error](5),
|
|
|
|
|
// func(x int) statereaderioeither.StateReaderIOEither[AppState, Config, error, string] {
|
|
|
|
|
// return statereaderioeither.Of[AppState, Config, error](fmt.Sprintf("value: %d", x))
|
|
|
|
|
// },
|
|
|
|
|
// )
|
2025-11-18 10:58:24 +01:00
|
|
|
func MonadChain[S, R, E, A, B any](fa StateReaderIOEither[S, R, E, A], f Kleisli[S, R, E, A, B]) StateReaderIOEither[S, R, E, B] {
|
2025-11-06 09:27:00 +01:00
|
|
|
return statet.MonadChain(
|
|
|
|
|
readerioeither.MonadChain[R, E, Pair[S, A], Pair[S, B]],
|
|
|
|
|
fa,
|
|
|
|
|
f,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// Chain is the curried version of [MonadChain].
|
|
|
|
|
// Returns a function that sequences computations.
|
|
|
|
|
//
|
|
|
|
|
// Example:
|
|
|
|
|
//
|
|
|
|
|
// stringify := statereaderioeither.Chain(func(x int) statereaderioeither.StateReaderIOEither[AppState, Config, error, string] {
|
|
|
|
|
// return statereaderioeither.Of[AppState, Config, error](fmt.Sprintf("%d", x))
|
|
|
|
|
// })
|
|
|
|
|
// result := function.Pipe1(statereaderioeither.Of[AppState, Config, error](42), stringify)
|
2025-11-18 10:58:24 +01:00
|
|
|
func Chain[S, R, E, A, B any](f Kleisli[S, R, E, A, B]) Operator[S, R, E, A, B] {
|
2025-11-06 09:27:00 +01:00
|
|
|
return statet.Chain[StateReaderIOEither[S, R, E, A]](
|
|
|
|
|
readerioeither.Chain[R, E, Pair[S, A], Pair[S, B]],
|
|
|
|
|
f,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// MonadAp applies a function wrapped in a StateReaderIOEither to a value wrapped in a StateReaderIOEither.
|
|
|
|
|
// 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 := statereaderioeither.Of[AppState, Config, error](func(x int) int { return x * 2 })
|
|
|
|
|
// fa := statereaderioeither.Of[AppState, Config, error](21)
|
|
|
|
|
// result := statereaderioeither.MonadAp(fab, fa) // Result contains 42
|
2025-11-06 09:27:00 +01:00
|
|
|
func MonadAp[B, S, R, E, A any](fab StateReaderIOEither[S, R, E, func(A) B], fa StateReaderIOEither[S, R, E, A]) StateReaderIOEither[S, R, E, B] {
|
|
|
|
|
return statet.MonadAp[StateReaderIOEither[S, R, E, A], StateReaderIOEither[S, R, E, B]](
|
|
|
|
|
readerioeither.MonadMap[R, E, Pair[S, A], Pair[S, B]],
|
|
|
|
|
readerioeither.MonadChain[R, E, Pair[S, func(A) B], Pair[S, B]],
|
|
|
|
|
fab,
|
|
|
|
|
fa,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// Ap is the curried version of [MonadAp].
|
|
|
|
|
// Returns a function that applies a wrapped function to the given wrapped value.
|
2025-11-06 09:27:00 +01:00
|
|
|
func Ap[B, S, R, E, A any](fa StateReaderIOEither[S, R, E, A]) Operator[S, R, E, func(A) B, B] {
|
|
|
|
|
return statet.Ap[StateReaderIOEither[S, R, E, A], StateReaderIOEither[S, R, E, B], StateReaderIOEither[S, R, E, func(A) B]](
|
|
|
|
|
readerioeither.Map[R, E, Pair[S, A], Pair[S, B]],
|
|
|
|
|
readerioeither.Chain[R, E, Pair[S, func(A) B], Pair[S, B]],
|
|
|
|
|
fa,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// FromReaderIOEither lifts a ReaderIOEither into a StateReaderIOEither.
|
|
|
|
|
// The state is passed through unchanged.
|
|
|
|
|
//
|
|
|
|
|
// Example:
|
|
|
|
|
//
|
|
|
|
|
// rioe := readerioeither.Of[Config, error](42)
|
|
|
|
|
// result := statereaderioeither.FromReaderIOEither[AppState](rioe)
|
2025-11-18 10:58:24 +01:00
|
|
|
func FromReaderIOEither[S, R, E, A any](fa ReaderIOEither[R, E, A]) StateReaderIOEither[S, R, E, A] {
|
2025-11-06 09:27:00 +01:00
|
|
|
return statet.FromF[StateReaderIOEither[S, R, E, A]](
|
|
|
|
|
readerioeither.MonadMap[R, E, A],
|
|
|
|
|
fa,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// FromReaderEither lifts a ReaderEither into a StateReaderIOEither.
|
|
|
|
|
// The state is passed through unchanged.
|
2025-11-06 09:27:00 +01:00
|
|
|
func FromReaderEither[S, R, E, A any](fa ReaderEither[R, E, A]) StateReaderIOEither[S, R, E, A] {
|
|
|
|
|
return FromReaderIOEither[S](readerioeither.FromReaderEither(fa))
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// FromIOEither lifts an IOEither into a StateReaderIOEither.
|
|
|
|
|
// The state is passed through unchanged and the context is ignored.
|
2025-11-06 09:27:00 +01:00
|
|
|
func FromIOEither[S, R, E, A any](fa IOEither[E, A]) StateReaderIOEither[S, R, E, A] {
|
|
|
|
|
return FromReaderIOEither[S](readerioeither.FromIOEither[R](fa))
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// FromState lifts a State computation into a StateReaderIOEither.
|
|
|
|
|
// The computation cannot fail (uses the error type parameter).
|
2025-11-06 09:27:00 +01:00
|
|
|
func FromState[R, E, S, A any](sa State[S, A]) StateReaderIOEither[S, R, E, A] {
|
|
|
|
|
return statet.FromState[StateReaderIOEither[S, R, E, A]](readerioeither.Of[R, E, Pair[S, A]], sa)
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// FromIO lifts an IO computation into a StateReaderIOEither.
|
|
|
|
|
// The state is passed through unchanged and the context is ignored.
|
2025-11-06 09:27:00 +01:00
|
|
|
func FromIO[S, R, E, A any](fa IO[A]) StateReaderIOEither[S, R, E, A] {
|
|
|
|
|
return FromReaderIOEither[S](readerioeither.FromIO[R, E](fa))
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// FromReader lifts a Reader into a StateReaderIOEither.
|
|
|
|
|
// The state is passed through unchanged.
|
2025-11-06 09:27:00 +01:00
|
|
|
func FromReader[S, E, R, A any](fa Reader[R, A]) StateReaderIOEither[S, R, E, A] {
|
|
|
|
|
return FromReaderIOEither[S](readerioeither.FromReader[E](fa))
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// FromEither lifts an Either into a StateReaderIOEither.
|
|
|
|
|
// The state is passed through unchanged and the context is ignored.
|
|
|
|
|
//
|
|
|
|
|
// Example:
|
|
|
|
|
//
|
|
|
|
|
// result := statereaderioeither.FromEither[AppState, Config](either.Right[error](42))
|
2025-11-06 09:27:00 +01:00
|
|
|
func FromEither[S, R, E, A any](ma Either[E, A]) StateReaderIOEither[S, R, E, A] {
|
|
|
|
|
return either.MonadFold(ma, Left[S, R, A, E], Right[S, R, E, A])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Combinators
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// Local runs a computation with a modified context.
|
|
|
|
|
// The function f transforms the context before passing it to the computation.
|
|
|
|
|
//
|
|
|
|
|
// Example:
|
|
|
|
|
//
|
|
|
|
|
// // Modify config before running computation
|
|
|
|
|
// withTimeout := statereaderioeither.Local[AppState, error, int](
|
|
|
|
|
// func(cfg Config) Config { return Config{...cfg, Timeout: 60} }
|
|
|
|
|
// )
|
|
|
|
|
// result := withTimeout(computation)
|
2025-11-06 09:27:00 +01:00
|
|
|
func Local[S, E, A, B, R1, R2 any](f func(R2) R1) func(StateReaderIOEither[S, R1, E, A]) StateReaderIOEither[S, R2, E, A] {
|
|
|
|
|
return func(ma StateReaderIOEither[S, R1, E, A]) StateReaderIOEither[S, R2, E, A] {
|
2025-11-10 18:44:14 +01:00
|
|
|
return function.Flow2(ma, readerioeither.Local[E, Pair[S, A]](f))
|
2025-11-06 09:27:00 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// Asks creates a computation that derives a value from the context.
|
|
|
|
|
// The function receives the context and returns a StateReaderIOEither.
|
|
|
|
|
//
|
|
|
|
|
// Example:
|
|
|
|
|
//
|
|
|
|
|
// getTimeout := statereaderioeither.Asks[AppState, Config, error, int](
|
|
|
|
|
// func(cfg Config) statereaderioeither.StateReaderIOEither[AppState, Config, error, int] {
|
|
|
|
|
// return statereaderioeither.Of[AppState, Config, error](cfg.Timeout)
|
|
|
|
|
// },
|
|
|
|
|
// )
|
2025-11-06 09:27:00 +01:00
|
|
|
func Asks[
|
|
|
|
|
S, R, E, A any,
|
|
|
|
|
](f func(R) StateReaderIOEither[S, R, E, A]) StateReaderIOEither[S, R, E, A] {
|
|
|
|
|
return func(s S) ReaderIOEither[R, E, Pair[S, A]] {
|
|
|
|
|
return func(r R) IOEither[E, Pair[S, A]] {
|
|
|
|
|
return f(r)(s)(r)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// FromEitherK lifts an Either-returning function into a Kleisli arrow for StateReaderIOEither.
|
|
|
|
|
//
|
|
|
|
|
// Example:
|
|
|
|
|
//
|
|
|
|
|
// validate := func(x int) either.Either[error, int] {
|
|
|
|
|
// if x > 0 { return either.Right[error](x) }
|
|
|
|
|
// return either.Left[int](errors.New("negative"))
|
|
|
|
|
// }
|
|
|
|
|
// kleisli := statereaderioeither.FromEitherK[AppState, Config](validate)
|
2025-11-18 10:58:24 +01:00
|
|
|
func FromEitherK[S, R, E, A, B any](f either.Kleisli[E, A, B]) Kleisli[S, R, E, A, B] {
|
2025-11-06 09:27:00 +01:00
|
|
|
return function.Flow2(
|
|
|
|
|
f,
|
|
|
|
|
FromEither[S, R, E, B],
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// FromIOK lifts an IO-returning function into a Kleisli arrow for StateReaderIOEither.
|
2025-11-18 10:58:24 +01:00
|
|
|
func FromIOK[S, R, E, A, B any](f func(A) IO[B]) Kleisli[S, R, E, A, B] {
|
2025-11-06 09:27:00 +01:00
|
|
|
return function.Flow2(
|
|
|
|
|
f,
|
|
|
|
|
FromIO[S, R, E, B],
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// FromIOEitherK lifts an IOEither-returning function into a Kleisli arrow for StateReaderIOEither.
|
2025-11-06 09:27:00 +01:00
|
|
|
func FromIOEitherK[
|
|
|
|
|
S, R, E, A, B any,
|
2025-11-18 10:58:24 +01:00
|
|
|
](f ioeither.Kleisli[E, A, B]) Kleisli[S, R, E, A, B] {
|
2025-11-06 09:27:00 +01:00
|
|
|
return function.Flow2(
|
|
|
|
|
f,
|
|
|
|
|
FromIOEither[S, R, E, B],
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// FromReaderIOEitherK lifts a ReaderIOEither-returning function into a Kleisli arrow for StateReaderIOEither.
|
2025-11-18 10:58:24 +01:00
|
|
|
func FromReaderIOEitherK[S, R, E, A, B any](f readerioeither.Kleisli[R, E, A, B]) Kleisli[S, R, E, A, B] {
|
2025-11-06 09:27:00 +01:00
|
|
|
return function.Flow2(
|
|
|
|
|
f,
|
|
|
|
|
FromReaderIOEither[S, R, E, B],
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// MonadChainReaderIOEitherK chains a StateReaderIOEither with a ReaderIOEither-returning function.
|
2025-11-18 10:58:24 +01:00
|
|
|
func MonadChainReaderIOEitherK[S, R, E, A, B any](ma StateReaderIOEither[S, R, E, A], f readerioeither.Kleisli[R, E, A, B]) StateReaderIOEither[S, R, E, B] {
|
2025-11-06 09:27:00 +01:00
|
|
|
return MonadChain(ma, FromReaderIOEitherK[S](f))
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// ChainReaderIOEitherK is the curried version of [MonadChainReaderIOEitherK].
|
2025-11-18 10:58:24 +01:00
|
|
|
func ChainReaderIOEitherK[S, R, E, A, B any](f readerioeither.Kleisli[R, E, A, B]) Operator[S, R, E, A, B] {
|
2025-11-06 09:27:00 +01:00
|
|
|
return Chain(FromReaderIOEitherK[S](f))
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// MonadChainIOEitherK chains a StateReaderIOEither with an IOEither-returning function.
|
2025-11-18 10:58:24 +01:00
|
|
|
func MonadChainIOEitherK[S, R, E, A, B any](ma StateReaderIOEither[S, R, E, A], f ioeither.Kleisli[E, A, B]) StateReaderIOEither[S, R, E, B] {
|
2025-11-06 09:27:00 +01:00
|
|
|
return MonadChain(ma, FromIOEitherK[S, R](f))
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// ChainIOEitherK is the curried version of [MonadChainIOEitherK].
|
2025-11-18 10:58:24 +01:00
|
|
|
func ChainIOEitherK[S, R, E, A, B any](f ioeither.Kleisli[E, A, B]) Operator[S, R, E, A, B] {
|
2025-11-06 09:27:00 +01:00
|
|
|
return Chain(FromIOEitherK[S, R](f))
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// MonadChainEitherK chains a StateReaderIOEither with an Either-returning function.
|
2025-11-18 10:58:24 +01:00
|
|
|
func MonadChainEitherK[S, R, E, A, B any](ma StateReaderIOEither[S, R, E, A], f either.Kleisli[E, A, B]) StateReaderIOEither[S, R, E, B] {
|
2025-11-06 09:27:00 +01:00
|
|
|
return MonadChain(ma, FromEitherK[S, R](f))
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-18 16:06:56 +01:00
|
|
|
// ChainEitherK is the curried version of [MonadChainEitherK].
|
2025-11-18 10:58:24 +01:00
|
|
|
func ChainEitherK[S, R, E, A, B any](f either.Kleisli[E, A, B]) Operator[S, R, E, A, B] {
|
2025-11-06 09:27:00 +01:00
|
|
|
return Chain(FromEitherK[S, R](f))
|
|
|
|
|
}
|