effect
Version:
The missing standard library for TypeScript, for writing production-grade software.
1,580 lines (1,550 loc) • 936 kB
text/typescript
/**
* @since 2.0.0
*/
import type * as RA from "./Array.js"
import type * as Cause from "./Cause.js"
import type * as Chunk from "./Chunk.js"
import type * as Clock from "./Clock.js"
import type { ConfigProvider } from "./ConfigProvider.js"
import type { Console } from "./Console.js"
import type * as Context from "./Context.js"
import type * as Deferred from "./Deferred.js"
import type * as Duration from "./Duration.js"
import type * as Either from "./Either.js"
import type { Equivalence } from "./Equivalence.js"
import type { ExecutionPlan } from "./ExecutionPlan.js"
import type { ExecutionStrategy } from "./ExecutionStrategy.js"
import type * as Exit from "./Exit.js"
import type * as Fiber from "./Fiber.js"
import type * as FiberId from "./FiberId.js"
import type * as FiberRef from "./FiberRef.js"
import type * as FiberRefs from "./FiberRefs.js"
import type * as FiberRefsPatch from "./FiberRefsPatch.js"
import type * as FiberStatus from "./FiberStatus.js"
import type { LazyArg } from "./Function.js"
import { dual } from "./Function.js"
import type * as HashMap from "./HashMap.js"
import type * as HashSet from "./HashSet.js"
import type { TypeLambda } from "./HKT.js"
import * as internalCause from "./internal/cause.js"
import * as console_ from "./internal/console.js"
import { TagProto } from "./internal/context.js"
import * as effect from "./internal/core-effect.js"
import * as core from "./internal/core.js"
import * as defaultServices from "./internal/defaultServices.js"
import * as circular from "./internal/effect/circular.js"
import * as internalExecutionPlan from "./internal/executionPlan.js"
import * as fiberRuntime from "./internal/fiberRuntime.js"
import * as layer from "./internal/layer.js"
import * as option_ from "./internal/option.js"
import * as query from "./internal/query.js"
import * as runtime_ from "./internal/runtime.js"
import * as schedule_ from "./internal/schedule.js"
import * as internalTracer from "./internal/tracer.js"
import type * as Layer from "./Layer.js"
import type * as LogLevel from "./LogLevel.js"
import type * as ManagedRuntime from "./ManagedRuntime.js"
import type * as Metric from "./Metric.js"
import type * as MetricLabel from "./MetricLabel.js"
import type * as Option from "./Option.js"
import type { Pipeable } from "./Pipeable.js"
import type { Predicate, Refinement } from "./Predicate.js"
import * as Random from "./Random.js"
import type * as Ref from "./Ref.js"
import * as Request from "./Request.js"
import type { RequestBlock } from "./RequestBlock.js"
import type { RequestResolver } from "./RequestResolver.js"
import type * as Runtime from "./Runtime.js"
import type * as RuntimeFlags from "./RuntimeFlags.js"
import type * as RuntimeFlagsPatch from "./RuntimeFlagsPatch.js"
import type * as Schedule from "./Schedule.js"
import * as Scheduler from "./Scheduler.js"
import type * as Scope from "./Scope.js"
import type * as Supervisor from "./Supervisor.js"
import type * as Tracer from "./Tracer.js"
import type {
Concurrency,
Contravariant,
Covariant,
EqualsWith,
NoExcessProperties,
NoInfer,
NotFunction
} from "./Types.js"
import type * as Unify from "./Unify.js"
import { isGeneratorFunction, type YieldWrap } from "./Utils.js"
/**
* @since 2.0.0
* @category Symbols
*/
export const EffectTypeId: unique symbol = core.EffectTypeId
/**
* @since 2.0.0
* @category Symbols
*/
export type EffectTypeId = typeof EffectTypeId
/**
* The `Effect` interface defines a value that describes a workflow or job,
* which can succeed or fail.
*
* **Details**
*
* The `Effect` interface represents a computation that can model a workflow
* involving various types of operations, such as synchronous, asynchronous,
* concurrent, and parallel interactions. It operates within a context of type
* `R`, and the result can either be a success with a value of type `A` or a
* failure with an error of type `E`. The `Effect` is designed to handle complex
* interactions with external resources, offering advanced features such as
* fiber-based concurrency, scheduling, interruption handling, and scalability.
* This makes it suitable for tasks that require fine-grained control over
* concurrency and error management.
*
* To execute an `Effect` value, you need a `Runtime`, which provides the
* environment necessary to run and manage the computation.
*
* @since 2.0.0
* @category Models
*/
export interface Effect<out A, out E = never, out R = never> extends Effect.Variance<A, E, R>, Pipeable {
readonly [Unify.typeSymbol]?: unknown
readonly [Unify.unifySymbol]?: EffectUnify<this>
readonly [Unify.ignoreSymbol]?: EffectUnifyIgnore
[Symbol.iterator](): EffectGenerator<Effect<A, E, R>>
}
/**
* @since 3.0.0
* @category Models
*/
export interface EffectGenerator<T extends Effect<any, any, any>> {
next(...args: ReadonlyArray<any>): IteratorResult<YieldWrap<T>, Effect.Success<T>>
}
/**
* @since 2.0.0
* @category Models
*/
export interface EffectUnify<A extends { [Unify.typeSymbol]?: any }>
extends Either.EitherUnify<A>, Option.OptionUnify<A>, Context.TagUnify<A>
{
Effect?: () => A[Unify.typeSymbol] extends Effect<infer A0, infer E0, infer R0> | infer _ ? Effect<A0, E0, R0> : never
}
/**
* @category Models
* @since 2.0.0
*/
export interface EffectUnifyIgnore {
Tag?: true
Option?: true
Either?: true
}
/**
* @category Type lambdas
* @since 2.0.0
*/
export interface EffectTypeLambda extends TypeLambda {
readonly type: Effect<this["Target"], this["Out1"], this["Out2"]>
}
/**
* @since 2.0.0
* @category Models
*/
export interface Blocked<out A, out E> extends Effect<A, E> {
readonly _op: "Blocked"
readonly effect_instruction_i0: RequestBlock
readonly effect_instruction_i1: Effect<A, E>
}
/**
* @since 2.0.0
* @category Models
*/
declare module "./Context.js" {
interface Tag<Id, Value> extends Effect<Value, never, Id> {
[Symbol.iterator](): EffectGenerator<Tag<Id, Value>>
}
interface Reference<Id, Value> extends Effect<Value> {
[Symbol.iterator](): EffectGenerator<Reference<Id, Value>>
}
interface TagUnifyIgnore {
Effect?: true
Either?: true
Option?: true
}
}
/**
* @since 2.0.0
* @category Models
*/
declare module "./Either.js" {
interface Left<E, A> extends Effect<A, E> {
readonly _tag: "Left"
[Symbol.iterator](): EffectGenerator<Left<E, A>>
}
interface Right<E, A> extends Effect<A, E> {
readonly _tag: "Right"
[Symbol.iterator](): EffectGenerator<Right<E, A>>
}
interface EitherUnifyIgnore {
Effect?: true
Tag?: true
Option?: true
}
}
/**
* @since 2.0.0
* @category Models
*/
declare module "./Option.js" {
interface None<A> extends Effect<A, Cause.NoSuchElementException> {
readonly _tag: "None"
[Symbol.iterator](): EffectGenerator<None<A>>
}
interface Some<A> extends Effect<A, Cause.NoSuchElementException> {
readonly _tag: "Some"
[Symbol.iterator](): EffectGenerator<Some<A>>
}
interface OptionUnifyIgnore {
Effect?: true
Tag?: true
Either?: true
}
}
/**
* @since 2.0.0
*/
export declare namespace Effect {
/**
* @since 2.0.0
* @category Models
*/
export interface Variance<out A, out E, out R> {
readonly [EffectTypeId]: VarianceStruct<A, E, R>
}
/**
* @since 2.0.0
* @category Models
*/
export interface VarianceStruct<out A, out E, out R> {
readonly _V: string
readonly _A: Covariant<A>
readonly _E: Covariant<E>
readonly _R: Covariant<R>
}
/**
* @since 2.0.0
* @category Effect Type Extractors
*/
export type Context<T extends Effect<any, any, any>> = [T] extends [Effect<infer _A, infer _E, infer _R>] ? _R : never
/**
* @since 2.0.0
* @category Effect Type Extractors
*/
export type Error<T extends Effect<any, any, any>> = [T] extends [Effect<infer _A, infer _E, infer _R>] ? _E : never
/**
* @since 2.0.0
* @category Effect Type Extractors
*/
export type Success<T extends Effect<any, any, any>> = [T] extends [Effect<infer _A, infer _E, infer _R>] ? _A : never
/**
* @since 3.15.5
* @category Effect Type Extractors
*/
export type AsEffect<T extends Effect<any, any, any>> = Effect<
T extends Effect<infer _A, infer _E, infer _R> ? _A : never,
T extends Effect<infer _A, infer _E, infer _R> ? _E : never,
T extends Effect<infer _A, infer _E, infer _R> ? _R : never
> extends infer Q ? Q : never
}
/**
* Checks if a given value is an `Effect` value.
*
* **When to Use**
*
* This function can be useful for checking the type of a value before
* attempting to operate on it as an `Effect` value. For example, you could use
* `Effect.isEffect` to check the type of a value before using it as an argument
* to a function that expects an `Effect` value.
*
* @since 2.0.0
* @category Guards
*/
export const isEffect: (u: unknown) => u is Effect<unknown, unknown, unknown> = core.isEffect
/**
* Returns an effect that caches its result for a specified `Duration`,
* known as "timeToLive" (TTL).
*
* **Details**
*
* This function is used to cache the result of an effect for a specified amount
* of time. This means that the first time the effect is evaluated, its result
* is computed and stored.
*
* If the effect is evaluated again within the specified `timeToLive`, the
* cached result will be used, avoiding recomputation.
*
* After the specified duration has passed, the cache expires, and the effect
* will be recomputed upon the next evaluation.
*
* **When to Use**
*
* Use this function when you have an effect that involves costly operations or
* computations, and you want to avoid repeating them within a short time frame.
*
* It's ideal for scenarios where the result of an effect doesn't change
* frequently and can be reused for a specified duration.
*
* By caching the result, you can improve efficiency and reduce unnecessary
* computations, especially in performance-critical applications.
*
* **Example**
*
* ```ts
* import { Effect, Console } from "effect"
*
* let i = 1
* const expensiveTask = Effect.promise<string>(() => {
* console.log("expensive task...")
* return new Promise((resolve) => {
* setTimeout(() => {
* resolve(`result ${i++}`)
* }, 100)
* })
* })
*
* const program = Effect.gen(function* () {
* const cached = yield* Effect.cachedWithTTL(expensiveTask, "150 millis")
* yield* cached.pipe(Effect.andThen(Console.log))
* yield* cached.pipe(Effect.andThen(Console.log))
* yield* Effect.sleep("100 millis")
* yield* cached.pipe(Effect.andThen(Console.log))
* })
*
* Effect.runFork(program)
* // Output:
* // expensive task...
* // result 1
* // result 1
* // expensive task...
* // result 2
* ```
*
* @see {@link cached} for a similar function that caches the result
* indefinitely.
* @see {@link cachedInvalidateWithTTL} for a similar function that includes an
* additional effect for manually invalidating the cached value.
*
* @since 2.0.0
* @category Caching
*/
export const cachedWithTTL: {
/**
* Returns an effect that caches its result for a specified `Duration`,
* known as "timeToLive" (TTL).
*
* **Details**
*
* This function is used to cache the result of an effect for a specified amount
* of time. This means that the first time the effect is evaluated, its result
* is computed and stored.
*
* If the effect is evaluated again within the specified `timeToLive`, the
* cached result will be used, avoiding recomputation.
*
* After the specified duration has passed, the cache expires, and the effect
* will be recomputed upon the next evaluation.
*
* **When to Use**
*
* Use this function when you have an effect that involves costly operations or
* computations, and you want to avoid repeating them within a short time frame.
*
* It's ideal for scenarios where the result of an effect doesn't change
* frequently and can be reused for a specified duration.
*
* By caching the result, you can improve efficiency and reduce unnecessary
* computations, especially in performance-critical applications.
*
* **Example**
*
* ```ts
* import { Effect, Console } from "effect"
*
* let i = 1
* const expensiveTask = Effect.promise<string>(() => {
* console.log("expensive task...")
* return new Promise((resolve) => {
* setTimeout(() => {
* resolve(`result ${i++}`)
* }, 100)
* })
* })
*
* const program = Effect.gen(function* () {
* const cached = yield* Effect.cachedWithTTL(expensiveTask, "150 millis")
* yield* cached.pipe(Effect.andThen(Console.log))
* yield* cached.pipe(Effect.andThen(Console.log))
* yield* Effect.sleep("100 millis")
* yield* cached.pipe(Effect.andThen(Console.log))
* })
*
* Effect.runFork(program)
* // Output:
* // expensive task...
* // result 1
* // result 1
* // expensive task...
* // result 2
* ```
*
* @see {@link cached} for a similar function that caches the result
* indefinitely.
* @see {@link cachedInvalidateWithTTL} for a similar function that includes an
* additional effect for manually invalidating the cached value.
*
* @since 2.0.0
* @category Caching
*/
(timeToLive: Duration.DurationInput): <A, E, R>(self: Effect<A, E, R>) => Effect<Effect<A, E>, never, R>
/**
* Returns an effect that caches its result for a specified `Duration`,
* known as "timeToLive" (TTL).
*
* **Details**
*
* This function is used to cache the result of an effect for a specified amount
* of time. This means that the first time the effect is evaluated, its result
* is computed and stored.
*
* If the effect is evaluated again within the specified `timeToLive`, the
* cached result will be used, avoiding recomputation.
*
* After the specified duration has passed, the cache expires, and the effect
* will be recomputed upon the next evaluation.
*
* **When to Use**
*
* Use this function when you have an effect that involves costly operations or
* computations, and you want to avoid repeating them within a short time frame.
*
* It's ideal for scenarios where the result of an effect doesn't change
* frequently and can be reused for a specified duration.
*
* By caching the result, you can improve efficiency and reduce unnecessary
* computations, especially in performance-critical applications.
*
* **Example**
*
* ```ts
* import { Effect, Console } from "effect"
*
* let i = 1
* const expensiveTask = Effect.promise<string>(() => {
* console.log("expensive task...")
* return new Promise((resolve) => {
* setTimeout(() => {
* resolve(`result ${i++}`)
* }, 100)
* })
* })
*
* const program = Effect.gen(function* () {
* const cached = yield* Effect.cachedWithTTL(expensiveTask, "150 millis")
* yield* cached.pipe(Effect.andThen(Console.log))
* yield* cached.pipe(Effect.andThen(Console.log))
* yield* Effect.sleep("100 millis")
* yield* cached.pipe(Effect.andThen(Console.log))
* })
*
* Effect.runFork(program)
* // Output:
* // expensive task...
* // result 1
* // result 1
* // expensive task...
* // result 2
* ```
*
* @see {@link cached} for a similar function that caches the result
* indefinitely.
* @see {@link cachedInvalidateWithTTL} for a similar function that includes an
* additional effect for manually invalidating the cached value.
*
* @since 2.0.0
* @category Caching
*/
<A, E, R>(self: Effect<A, E, R>, timeToLive: Duration.DurationInput): Effect<Effect<A, E>, never, R>
} = circular.cached
/**
* Caches an effect's result for a specified duration and allows manual
* invalidation before expiration.
*
* **Details**
*
* This function behaves similarly to {@link cachedWithTTL} by caching the
* result of an effect for a specified period of time. However, it introduces an
* additional feature: it provides an effect that allows you to manually
* invalidate the cached result before it naturally expires.
*
* This gives you more control over the cache, allowing you to refresh the
* result when needed, even if the original cache has not yet expired.
*
* Once the cache is invalidated, the next time the effect is evaluated, the
* result will be recomputed, and the cache will be refreshed.
*
* **When to Use**
*
* Use this function when you have an effect whose result needs to be cached for
* a certain period, but you also want the option to refresh the cache manually
* before the expiration time.
*
* This is useful when you need to ensure that the cached data remains valid for
* a certain period but still want to invalidate it if the underlying data
* changes or if you want to force a recomputation.
*
* **Example**
*
* ```ts
* import { Effect, Console } from "effect"
*
* let i = 1
* const expensiveTask = Effect.promise<string>(() => {
* console.log("expensive task...")
* return new Promise((resolve) => {
* setTimeout(() => {
* resolve(`result ${i++}`)
* }, 100)
* })
* })
*
* const program = Effect.gen(function* () {
* const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL(
* expensiveTask,
* "1 hour"
* )
* yield* cached.pipe(Effect.andThen(Console.log))
* yield* cached.pipe(Effect.andThen(Console.log))
* yield* invalidate
* yield* cached.pipe(Effect.andThen(Console.log))
* })
*
* Effect.runFork(program)
* // Output:
* // expensive task...
* // result 1
* // result 1
* // expensive task...
* // result 2
* ```
*
* @see {@link cached} for a similar function that caches the result
* indefinitely.
* @see {@link cachedWithTTL} for a similar function that caches the result for
* a specified duration but does not include an effect for manual invalidation.
*
* @since 2.0.0
* @category Caching
*/
export const cachedInvalidateWithTTL: {
/**
* Caches an effect's result for a specified duration and allows manual
* invalidation before expiration.
*
* **Details**
*
* This function behaves similarly to {@link cachedWithTTL} by caching the
* result of an effect for a specified period of time. However, it introduces an
* additional feature: it provides an effect that allows you to manually
* invalidate the cached result before it naturally expires.
*
* This gives you more control over the cache, allowing you to refresh the
* result when needed, even if the original cache has not yet expired.
*
* Once the cache is invalidated, the next time the effect is evaluated, the
* result will be recomputed, and the cache will be refreshed.
*
* **When to Use**
*
* Use this function when you have an effect whose result needs to be cached for
* a certain period, but you also want the option to refresh the cache manually
* before the expiration time.
*
* This is useful when you need to ensure that the cached data remains valid for
* a certain period but still want to invalidate it if the underlying data
* changes or if you want to force a recomputation.
*
* **Example**
*
* ```ts
* import { Effect, Console } from "effect"
*
* let i = 1
* const expensiveTask = Effect.promise<string>(() => {
* console.log("expensive task...")
* return new Promise((resolve) => {
* setTimeout(() => {
* resolve(`result ${i++}`)
* }, 100)
* })
* })
*
* const program = Effect.gen(function* () {
* const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL(
* expensiveTask,
* "1 hour"
* )
* yield* cached.pipe(Effect.andThen(Console.log))
* yield* cached.pipe(Effect.andThen(Console.log))
* yield* invalidate
* yield* cached.pipe(Effect.andThen(Console.log))
* })
*
* Effect.runFork(program)
* // Output:
* // expensive task...
* // result 1
* // result 1
* // expensive task...
* // result 2
* ```
*
* @see {@link cached} for a similar function that caches the result
* indefinitely.
* @see {@link cachedWithTTL} for a similar function that caches the result for
* a specified duration but does not include an effect for manual invalidation.
*
* @since 2.0.0
* @category Caching
*/
(timeToLive: Duration.DurationInput): <A, E, R>(
self: Effect<A, E, R>
) => Effect<[Effect<A, E>, Effect<void>], never, R>
/**
* Caches an effect's result for a specified duration and allows manual
* invalidation before expiration.
*
* **Details**
*
* This function behaves similarly to {@link cachedWithTTL} by caching the
* result of an effect for a specified period of time. However, it introduces an
* additional feature: it provides an effect that allows you to manually
* invalidate the cached result before it naturally expires.
*
* This gives you more control over the cache, allowing you to refresh the
* result when needed, even if the original cache has not yet expired.
*
* Once the cache is invalidated, the next time the effect is evaluated, the
* result will be recomputed, and the cache will be refreshed.
*
* **When to Use**
*
* Use this function when you have an effect whose result needs to be cached for
* a certain period, but you also want the option to refresh the cache manually
* before the expiration time.
*
* This is useful when you need to ensure that the cached data remains valid for
* a certain period but still want to invalidate it if the underlying data
* changes or if you want to force a recomputation.
*
* **Example**
*
* ```ts
* import { Effect, Console } from "effect"
*
* let i = 1
* const expensiveTask = Effect.promise<string>(() => {
* console.log("expensive task...")
* return new Promise((resolve) => {
* setTimeout(() => {
* resolve(`result ${i++}`)
* }, 100)
* })
* })
*
* const program = Effect.gen(function* () {
* const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL(
* expensiveTask,
* "1 hour"
* )
* yield* cached.pipe(Effect.andThen(Console.log))
* yield* cached.pipe(Effect.andThen(Console.log))
* yield* invalidate
* yield* cached.pipe(Effect.andThen(Console.log))
* })
*
* Effect.runFork(program)
* // Output:
* // expensive task...
* // result 1
* // result 1
* // expensive task...
* // result 2
* ```
*
* @see {@link cached} for a similar function that caches the result
* indefinitely.
* @see {@link cachedWithTTL} for a similar function that caches the result for
* a specified duration but does not include an effect for manual invalidation.
*
* @since 2.0.0
* @category Caching
*/
<A, E, R>(self: Effect<A, E, R>, timeToLive: Duration.DurationInput): Effect<[Effect<A, E>, Effect<void>], never, R>
} = circular.cachedInvalidateWithTTL
/**
* Returns an effect that lazily computes a result and caches it for subsequent
* evaluations.
*
* **Details**
*
* This function wraps an effect and ensures that its result is computed only
* once. Once the result is computed, it is cached, meaning that subsequent
* evaluations of the same effect will return the cached result without
* re-executing the logic.
*
* **When to Use**
*
* Use this function when you have an expensive or time-consuming operation that
* you want to avoid repeating. The first evaluation will compute the result,
* and all following evaluations will immediately return the cached value,
* improving performance and reducing unnecessary work.
*
* **Example**
*
* ```ts
* import { Effect, Console } from "effect"
*
* let i = 1
* const expensiveTask = Effect.promise<string>(() => {
* console.log("expensive task...")
* return new Promise((resolve) => {
* setTimeout(() => {
* resolve(`result ${i++}`)
* }, 100)
* })
* })
*
* const program = Effect.gen(function* () {
* console.log("non-cached version:")
* yield* expensiveTask.pipe(Effect.andThen(Console.log))
* yield* expensiveTask.pipe(Effect.andThen(Console.log))
* console.log("cached version:")
* const cached = yield* Effect.cached(expensiveTask)
* yield* cached.pipe(Effect.andThen(Console.log))
* yield* cached.pipe(Effect.andThen(Console.log))
* })
*
* Effect.runFork(program)
* // Output:
* // non-cached version:
* // expensive task...
* // result 1
* // expensive task...
* // result 2
* // cached version:
* // expensive task...
* // result 3
* // result 3
* ```
*
* @see {@link cachedWithTTL} for a similar function that includes a
* time-to-live duration for the cached value.
* @see {@link cachedInvalidateWithTTL} for a similar function that includes an
* additional effect for manually invalidating the cached value.
*
* @since 2.0.0
* @category Caching
*/
export const cached: <A, E, R>(self: Effect<A, E, R>) => Effect<Effect<A, E, R>> = effect.memoize
/**
* Returns a memoized version of a function with effects, reusing results for
* the same inputs.
*
* **Details**
*
* This function creates a memoized version of a given function that performs an
* effect. Memoization ensures that once a result is computed for a specific
* input, it is stored and reused for subsequent calls with the same input,
* reducing the need to recompute the result.
*
* The function can optionally take an `Equivalence` parameter to
* determine how inputs are compared for caching purposes.
*
* **When to Use**
*
* Use this function when you have a function that performs an effect and you
* want to avoid recomputing the result for the same input multiple times.
*
* It's ideal for functions that produce deterministic results based on their
* inputs, and you want to improve performance by caching the output.
*
* This is particularly useful in scenarios where the function involves
* expensive calculations or operations that should be avoided after the first
* execution with the same parameters.
*
* **Example**
*
* ```ts
* import { Effect, Random } from "effect"
*
* const program = Effect.gen(function* () {
* const randomNumber = (n: number) => Random.nextIntBetween(1, n)
* console.log("non-memoized version:")
* console.log(yield* randomNumber(10))
* console.log(yield* randomNumber(10))
*
* console.log("memoized version:")
* const memoized = yield* Effect.cachedFunction(randomNumber)
* console.log(yield* memoized(10))
* console.log(yield* memoized(10))
* })
*
* Effect.runFork(program)
* // Example Output:
* // non-memoized version:
* // 2
* // 8
* // memoized version:
* // 5
* // 5
* ```
*
* @since 2.0.0
* @category Caching
*/
export const cachedFunction: <A, B, E, R>(
f: (a: A) => Effect<B, E, R>,
eq?: Equivalence<A>
) => Effect<(a: A) => Effect<B, E, R>> = circular.cachedFunction
/**
* Returns an effect that executes only once, regardless of how many times it's
* called.
*
* **Details**
*
* This function ensures that a specific effect is executed only a single time,
* no matter how many times it is invoked. The result of the effect will be
* cached, and subsequent calls to the effect will immediately return the cached
* result without re-executing the original logic.
*
* **When to Use**
*
* Use this function when you need to perform a task only once, regardless of
* how many times the effect is triggered. It's particularly useful when you
* have initialization tasks, logging, or other one-time actions that should not
* be repeated. This can help optimize performance and avoid redundant actions.
*
* **Example**
*
* ```ts
* import { Effect, Console } from "effect"
*
* const program = Effect.gen(function* () {
* const task1 = Console.log("task1")
* yield* Effect.repeatN(task1, 2)
* const task2 = yield* Effect.once(Console.log("task2"))
* yield* Effect.repeatN(task2, 2)
* })
*
* Effect.runFork(program)
* // Output:
* // task1
* // task1
* // task1
* // task2
* ```
*
* @since 2.0.0
* @category Caching
*/
export const once: <A, E, R>(self: Effect<A, E, R>) => Effect<Effect<void, E, R>> = effect.once
/**
* Combines multiple effects into one, returning results based on the input
* structure.
*
* **Details**
*
* Use this function when you need to run multiple effects and combine their
* results into a single output. It supports tuples, iterables, structs, and
* records, making it flexible for different input types.
*
* For instance, if the input is a tuple:
*
* ```ts skip-type-checking
* // ┌─── a tuple of effects
* // ▼
* Effect.all([effect1, effect2, ...])
* ```
*
* the effects are executed sequentially, and the result is a new effect
* containing the results as a tuple. The results in the tuple match the order
* of the effects passed to `Effect.all`.
*
* **Concurrency**
*
* You can control the execution order (e.g., sequential vs. concurrent) using
* the `concurrency` option.
*
* **Short-Circuiting Behavior**
*
* This function stops execution on the first error it encounters, this is
* called "short-circuiting". If any effect in the collection fails, the
* remaining effects will not run, and the error will be propagated. To change
* this behavior, you can use the `mode` option, which allows all effects to run
* and collect results as `Either` or `Option`.
*
* **The `mode` option**
*
* The `{ mode: "either" }` option changes the behavior of `Effect.all` to
* ensure all effects run, even if some fail. Instead of stopping on the first
* failure, this mode collects both successes and failures, returning an array
* of `Either` instances where each result is either a `Right` (success) or a
* `Left` (failure).
*
* Similarly, the `{ mode: "validate" }` option uses `Option` to indicate
* success or failure. Each effect returns `None` for success and `Some` with
* the error for failure.
*
* **Example** (Combining Effects in Tuples)
*
* ```ts
* import { Effect, Console } from "effect"
*
* const tupleOfEffects = [
* Effect.succeed(42).pipe(Effect.tap(Console.log)),
* Effect.succeed("Hello").pipe(Effect.tap(Console.log))
* ] as const
*
* // ┌─── Effect<[number, string], never, never>
* // ▼
* const resultsAsTuple = Effect.all(tupleOfEffects)
*
* Effect.runPromise(resultsAsTuple).then(console.log)
* // Output:
* // 42
* // Hello
* // [ 42, 'Hello' ]
* ```
*
* **Example** (Combining Effects in Iterables)
*
* ```ts
* import { Effect, Console } from "effect"
*
* const iterableOfEffects: Iterable<Effect.Effect<number>> = [1, 2, 3].map(
* (n) => Effect.succeed(n).pipe(Effect.tap(Console.log))
* )
*
* // ┌─── Effect<number[], never, never>
* // ▼
* const resultsAsArray = Effect.all(iterableOfEffects)
*
* Effect.runPromise(resultsAsArray).then(console.log)
* // Output:
* // 1
* // 2
* // 3
* // [ 1, 2, 3 ]
* ```
*
* **Example** (Combining Effects in Structs)
*
* ```ts
* import { Effect, Console } from "effect"
*
* const structOfEffects = {
* a: Effect.succeed(42).pipe(Effect.tap(Console.log)),
* b: Effect.succeed("Hello").pipe(Effect.tap(Console.log))
* }
*
* // ┌─── Effect<{ a: number; b: string; }, never, never>
* // ▼
* const resultsAsStruct = Effect.all(structOfEffects)
*
* Effect.runPromise(resultsAsStruct).then(console.log)
* // Output:
* // 42
* // Hello
* // { a: 42, b: 'Hello' }
* ```
*
* **Example** (Combining Effects in Records)
*
* ```ts
* import { Effect, Console } from "effect"
*
* const recordOfEffects: Record<string, Effect.Effect<number>> = {
* key1: Effect.succeed(1).pipe(Effect.tap(Console.log)),
* key2: Effect.succeed(2).pipe(Effect.tap(Console.log))
* }
*
* // ┌─── Effect<{ [x: string]: number; }, never, never>
* // ▼
* const resultsAsRecord = Effect.all(recordOfEffects)
*
* Effect.runPromise(resultsAsRecord).then(console.log)
* // Output:
* // 1
* // 2
* // { key1: 1, key2: 2 }
* ```
*
* **Example** (Short-Circuiting Behavior)
*
* ```ts
* import { Effect, Console } from "effect"
*
* const program = Effect.all([
* Effect.succeed("Task1").pipe(Effect.tap(Console.log)),
* Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)),
* // Won't execute due to earlier failure
* Effect.succeed("Task3").pipe(Effect.tap(Console.log))
* ])
*
* Effect.runPromiseExit(program).then(console.log)
* // Output:
* // Task1
* // {
* // _id: 'Exit',
* // _tag: 'Failure',
* // cause: { _id: 'Cause', _tag: 'Fail', failure: 'Task2: Oh no!' }
* // }
* ```
*
* **Example** (Collecting Results with `mode: "either"`)
*
* ```ts
* import { Effect, Console } from "effect"
*
* const effects = [
* Effect.succeed("Task1").pipe(Effect.tap(Console.log)),
* Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)),
* Effect.succeed("Task3").pipe(Effect.tap(Console.log))
* ]
*
* const program = Effect.all(effects, { mode: "either" })
*
* Effect.runPromiseExit(program).then(console.log)
* // Output:
* // Task1
* // Task3
* // {
* // _id: 'Exit',
* // _tag: 'Success',
* // value: [
* // { _id: 'Either', _tag: 'Right', right: 'Task1' },
* // { _id: 'Either', _tag: 'Left', left: 'Task2: Oh no!' },
* // { _id: 'Either', _tag: 'Right', right: 'Task3' }
* // ]
* // }
* ```
*
* **Example** (Collecting Results with `mode: "validate"`)
*
* ```ts
* import { Effect, Console } from "effect"
*
* const effects = [
* Effect.succeed("Task1").pipe(Effect.tap(Console.log)),
* Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)),
* Effect.succeed("Task3").pipe(Effect.tap(Console.log))
* ]
*
* const program = Effect.all(effects, { mode: "validate" })
*
* Effect.runPromiseExit(program).then((result) => console.log("%o", result))
* // Output:
* // Task1
* // Task3
* // {
* // _id: 'Exit',
* // _tag: 'Failure',
* // cause: {
* // _id: 'Cause',
* // _tag: 'Fail',
* // failure: [
* // { _id: 'Option', _tag: 'None' },
* // { _id: 'Option', _tag: 'Some', value: 'Task2: Oh no!' },
* // { _id: 'Option', _tag: 'None' }
* // ]
* // }
* // }
* ```
*
* @see {@link forEach} for iterating over elements and applying an effect.
* @see {@link allWith} for a data-last version of this function.
*
* @since 2.0.0
* @category Collecting
*/
export const all: <
const Arg extends Iterable<Effect<any, any, any>> | Record<string, Effect<any, any, any>>,
O extends NoExcessProperties<{
readonly concurrency?: Concurrency | undefined
readonly batching?: boolean | "inherit" | undefined
readonly discard?: boolean | undefined
readonly mode?: "default" | "validate" | "either" | undefined
readonly concurrentFinalizers?: boolean | undefined
}, O>
>(arg: Arg, options?: O) => All.Return<Arg, O> = fiberRuntime.all
/**
* A data-last version of {@link all}, designed for use in pipelines.
*
* **When to Use**
*
* This function enables you to combine multiple effects and customize execution
* options such as concurrency levels. This version is useful in functional
* pipelines where you first define your data and then apply operations to it.
*
* **Example**
*
* ```ts
* import { Effect, pipe } from "effect"
*
* const task1 = Effect.succeed(1).pipe(
* Effect.delay("200 millis"),
* Effect.tap(Effect.log("task1 done"))
* )
*
* const task2 = Effect.succeed("hello").pipe(
* Effect.delay("100 millis"),
* Effect.tap(Effect.log("task2 done"))
* )
*
* const program = pipe(
* [task1, task2],
* // Run both effects concurrently using the concurrent option
* Effect.allWith({ concurrency: 2 })
* )
*
* Effect.runPromise(program).then(console.log)
* // Output:
* // timestamp=... level=INFO fiber=#3 message="task2 done"
* // timestamp=... level=INFO fiber=#2 message="task1 done"
* // [ 1, 'hello' ]
* ```
*
* @since 2.0.0
* @category Collecting
*/
export const allWith: <
O extends NoExcessProperties<{
readonly concurrency?: Concurrency | undefined
readonly batching?: boolean | "inherit" | undefined
readonly discard?: boolean | undefined
readonly mode?: "default" | "validate" | "either" | undefined
readonly concurrentFinalizers?: boolean | undefined
}, O>
>(
options?: O
) => <const Arg extends Iterable<Effect<any, any, any>> | Record<string, Effect<any, any, any>>>(
arg: Arg
) => All.Return<Arg, O> = fiberRuntime.allWith
/**
* @since 2.0.0
*/
export declare namespace All {
/**
* @since 2.0.0
*/
export type EffectAny = Effect<any, any, any>
/**
* @since 2.0.0
*/
export type ReturnIterable<T extends Iterable<EffectAny>, Discard extends boolean, Mode> = [T] extends
[Iterable<Effect.Variance<infer R0, infer L0, infer R>>] ? Effect<
Discard extends true ? void : Mode extends "either" ? Array<Either.Either<R0, L0>> : Array<R0>,
Mode extends "either" ? never
: Mode extends "validate" ? Array<Option.Option<L0>>
: L0,
R
>
: never
/**
* @since 2.0.0
*/
export type ReturnTuple<T extends ReadonlyArray<unknown>, Discard extends boolean, Mode> = Effect<
Discard extends true ? void
: T[number] extends never ? []
: Mode extends "either" ? {
-readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ?
Either.Either<_A, _E>
: never
}
: { -readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ? _A : never },
Mode extends "either" ? never
: T[number] extends never ? never
: Mode extends "validate" ? {
-readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ? Option.Option<_E>
: never
}
: [T[number]] extends [{ [EffectTypeId]: { _E: (_: never) => infer E } }] ? E
: never,
T[number] extends never ? never
: [T[number]] extends [{ [EffectTypeId]: { _R: (_: never) => infer R } }] ? R
: never
> extends infer X ? X : never
/**
* @since 2.0.0
*/
export type ReturnObject<T, Discard extends boolean, Mode> = [T] extends [{ [K: string]: EffectAny }] ? Effect<
Discard extends true ? void
: Mode extends "either" ? {
-readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ?
Either.Either<_A, _E>
: never
}
: { -readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ? _A : never },
Mode extends "either" ? never
: keyof T extends never ? never
: Mode extends "validate" ? {
-readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ? Option.Option<_E>
: never
}
: [T[keyof T]] extends [{ [EffectTypeId]: { _E: (_: never) => infer E } }] ? E
: never,
keyof T extends never ? never
: [T[keyof T]] extends [{ [EffectTypeId]: { _R: (_: never) => infer R } }] ? R
: never
>
: never
/**
* @since 2.0.0
*/
export type IsDiscard<A> = [Extract<A, { readonly discard: true }>] extends [never] ? false : true
/**
* @since 2.0.0
*/
export type ExtractMode<A> = [A] extends [{ mode: infer M }] ? M : "default"
/**
* @since 2.0.0
*/
export type Return<
Arg extends Iterable<EffectAny> | Record<string, EffectAny>,
O extends NoExcessProperties<{
readonly concurrency?: Concurrency | undefined
readonly batching?: boolean | "inherit" | undefined
readonly discard?: boolean | undefined
readonly mode?: "default" | "validate" | "either" | undefined
readonly concurrentFinalizers?: boolean | undefined
}, O>
> = [Arg] extends [ReadonlyArray<EffectAny>] ? ReturnTuple<Arg, IsDiscard<O>, ExtractMode<O>>
: [Arg] extends [Iterable<EffectAny>] ? ReturnIterable<Arg, IsDiscard<O>, ExtractMode<O>>
: [Arg] extends [Record<string, EffectAny>] ? ReturnObject<Arg, IsDiscard<O>, ExtractMode<O>>
: never
}
/**
* Evaluates and runs each effect in the iterable, collecting only the
* successful results while discarding failures.
*
* **Details**
*
* This function function processes an iterable of effects and runs each one. If
* an effect is successful, its result is collected; if it fails, the result is
* discarded. This ensures that only successful outcomes are kept.
*
* **Options**
*
* The function also allows you to customize how the effects are handled by
* specifying options such as concurrency, batching, and how finalizers behave.
* These options provide flexibility in running the effects concurrently or
* adjusting other execution details.
*
* **Example**
*
* ```ts
* import { Effect } from "effect"
*
* const tasks = [
* Effect.succeed(1),
* Effect.fail("Error 1"),
* Effect.succeed(2),
* Effect.fail("Error 2")
* ]
*
* const program = Effect.gen(function*() {
* const successfulResults = yield* Effect.allSuccesses(tasks)
* console.log(successfulResults)
* })
*
* Effect.runFork(program)
* // Output: [1, 2]
*
* ```
*
* @since 2.0.0
* @category Collecting
*/
export const allSuccesses: <X extends Effect<any, any, any>>(
elements: Iterable<X>,
options?:
| {
readonly concurrency?: Concurrency | undefined
readonly batching?: boolean | "inherit" | undefined
readonly concurrentFinalizers?: boolean | undefined
}
| undefined
) => Effect<Array<Effect.Success<X>>, never, Effect.Context<X>> = fiberRuntime.allSuccesses
/**
* Drops elements until the effectful predicate returns `true`.
*
* **Details**
*
* This function processes a collection of elements and uses an effectful
* predicate to determine when to stop dropping elements. It drops elements from
* the beginning of the collection until the predicate returns `true`.
*
* The predicate is a function that takes an element and its index in the
* collection and returns an effect that evaluates to a boolean.
*
* Once the predicate returns `true`, the remaining elements of the collection
* are returned.
*
* **Note**: The first element for which the predicate returns `true` is also
* dropped.
*
* **When to Use**
*
* This function allows you to conditionally skip over a part of the collection
* based on some criteria defined in the predicate.
*
* **Example**
*
* ```ts
* import { Effect } from "effect"
*
* const numbers = [1, 2, 3, 4, 5, 6]
* const predicate = (n: number, i: number) => Effect.succeed(n > 3)
*
* const program = Effect.gen(function*() {
* const result = yield* Effect.dropUntil(numbers, predicate)
* console.log(result)
* })
*
* Effect.runFork(program)
* // Output: [5, 6]
* ```
*
* @see {@link dropWhile} for a similar function that drops elements while the
* predicate returns `true`.
*
* @since 2.0.0
* @category Collecting
*/
export const dropUntil: {
/**
* Drops elements until the effectful predicate returns `true`.
*
* **Details**
*
* This function processes a collection of elements and uses an effectful
* predicate to determine when to stop dropping elements. It drops elements from
* the beginning of the collection until the predicate returns `true`.
*
* The predicate is a function that takes an element and its index in the
* collection and returns an effect that evaluates to a boolean.
*
* Once the predicate returns `true`, the remaining elements of the collection
* are returned.
*
* **Note**: The first element for which the predicate returns `true` is also
* dropped.
*
* **When to Use**
*
* This function allows you to conditionally skip over a part of the collection
* based on some criteria defined in the predicate.
*
* **Example**
*
* ```ts
* import { Effect } from "effect"
*
* const numbers = [1, 2, 3, 4, 5, 6]
* const predicate = (n: number, i: number) => Effect.succeed(n > 3)
*
* const program = Effect.gen(function*() {
* const result = yield* Effect.dropUntil(numbers, predicate)
* console.log(result)
* })
*
* Effect.runFork(program)
* // Output: [5, 6]
* ```
*
* @see {@link dropWhile} for a similar function that drops elements while the
* predicate returns `true`.
*
* @since 2.0.0
* @category Collecting
*/
<A, E, R>(predicate: (a: NoInfer<A>, i: number) => Effect<boolean, E, R>): (elements: Iterable<A>) => Effect<Array<A>, E, R>
/**
* Drops elements until the effectful predicate returns `true`.
*
* **Details**
*
* This function processes a collection of elements and uses an effectful
* predicate to determine when to stop dropping elements. It drops elements from
* the beginning of the collection until the predicate returns `true`.
*
* The predicate is a function that takes an element and its index in the
* collection and returns an effect that evaluates to a boolean.
*
* Once the predicate returns `true`, the remaining elements of the collection
* are returned.
*
* **Note**: The first element for which the predicate returns `true` is also
* dropped.
*
* **When to Use**
*
* This function allows you to conditionally skip over a part of the collection
* based on some criteria defined in the predicate.
*
* **Example**
*
* ```ts
* import { Effect } from "effect"
*
* const numbers = [1, 2, 3, 4, 5, 6]
* const predicate = (n: number, i: number) => Effect.succeed(n > 3)
*
* const program = Effect.gen(function*() {
* const result = yield* Effect.dropUntil(numbers, predicate)
* console.log(result)
* })
*
* Effect.runFork(program)
* // Output: [5, 6]
* ```
*
* @see {@link dropWhile} for a similar function that drops elements while the
* predicate returns `true`.
*
* @since 2.0.0
* @category Collecting
*/
<A, E, R>(
elements: Iterable<A>,
predicate: (a: A, i: number) => Effect<boolean, E, R>
): Effect<Array<A>, E, R>
} = effect.dropUntil
/**
* Drops elements as long as the predicate returns `true`.
*
* **Details**
*
* This function processes a collection of elements and uses a predicate to
* decide whether to drop an element.
*
* The predicate is a function that takes an element and its index, and it
* returns an effect that evaluates to a boolean.
*
* As long as the predicate returns `true`, elements will continue to be dropped
* from the collection.
*
* Once the predicate returns `false`, the remaining elements are kept.
*
* **When to Use**
*
* This function allows you to discard elements from the start of a collection
* based on a condition, and only keep the rest when the condition no longer
* holds.
*
* **Example**
*
* ```ts
* import { Effect } from "effect"
*
* const numbers = [1, 2, 3, 4, 5, 6]
* const predicate = (n: number, i: number) => Effect.succeed(n <= 3)
*
* const program = Effect.gen(function*() {
* const result = yield* Effect.dropWhile(numbers, predicate)
* console.log(result)
* })
*
* Effect.runFork(program)
* // Output: [4, 5, 6]
* ```
*
* @see {@link dropUntil} for a similar function that drops elements until the
* predicate returns `true`.
*
* @since 2.0.0
* @category Collecting
*/
export const dropWhile: {
/**
* Drops elements as long as the predicate returns `true`.
*
* **Details**
*
* This function processes a collection of elements and uses a predicate to
* decide whether to drop an element.
*
* The predicate is a function that takes an element and its index, and it
* returns an effect that evaluates to a boolean.
*
* As long as the predicate returns `true`, elements will continue to be dropped
* from the collection.
*
* Once the predicate returns `false`, the remaining elements are kept.
*
* **When to Use**
*
* This function allows you to discard elements from the start of a collection
* based on a condition, and only keep the rest when the condition no longer
* holds.
*
* **Example**
*
* ```ts
* import { Effect } from "effect"
*
* const numbers = [1, 2, 3, 4, 5, 6]
* const predicate = (n: number, i: number) => Effect.succeed(n <= 3)
*
* const program = Effect.gen(function*() {
* const result = yield* Effect.dropWhile(numbers, predicate)
* console.log(result)
* })
*
* Effect.runFork(program)
* // Output: [4, 5, 6]
* ```
*
* @see {@link dropUntil} for a similar function that drops elements until the
* predicate returns `true`.
*
* @since 2.0.0
* @category Collecting
*/
<A, E, R>(predicate: (a: NoInfer<A>, i: number) => Effect<boolean, E, R>): (elements: Iterable<A>) => Effect<Array<A>, E, R>
/**
* Drops elements as long as the predicate returns `true`.
*
* **Details**
*
* This function processes a collection of elements and uses a predicate to
* decide whether to drop an element.
*
* The predicate is a function that takes an element and its index, and it
* returns an effect that evaluates to a boolean.
*
* As long as the predicate returns `true`, elements will continue to be dropped
* from the collection.
*
* Once the predicate returns `false`, the remaining elements are kept.
*
* **When to Use**
*
* This function allows you to discard elements from the start of a collection
* based on a condition, and only keep the rest when the condition no longer
* holds.
*
* **Example**
*
* ```ts
* import { Effect } from "effect"
*
* const numbers = [1, 2, 3, 4, 5, 6]
* const predicate = (n: number, i: nu