effect
Version:
The missing standard library for TypeScript, for writing production-grade software.
1,350 lines (1,349 loc) • 332 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.forEach = exports.fnUntraced = exports.fn = exports.flipWith = exports.flip = exports.flatten = exports.flatMap = exports.firstSuccessOf = exports.findFirst = exports.finalizersMask = exports.filterOrFail = exports.filterOrElse = exports.filterOrDieMessage = exports.filterOrDie = exports.filterMap = exports.filterEffectOrFail = exports.filterEffectOrElse = exports.filter = exports.fiberIdWith = exports.fiberId = exports.failSync = exports.failCauseSync = exports.failCause = exports.fail = exports.exit = exports.exists = exports.every = exports.eventually = exports.ensuringChildren = exports.ensuringChild = exports.ensuring = exports.either = exports.dropWhile = exports.dropUntil = exports.disconnect = exports.diffFiberRefs = exports.dieSync = exports.dieMessage = exports.die = exports.descriptorWith = exports.descriptor = exports.delay = exports.daemonChildren = exports.custom = exports.currentSpan = exports.currentParentSpan = exports.contextWithEffect = exports.contextWith = exports.context = exports.consoleWith = exports.console = exports.configProviderWith = exports.clockWith = exports.clock = exports.checkInterruptible = exports.cause = exports.catchTags = exports.catchTag = exports.catchSomeDefect = exports.catchSomeCause = exports.catchSome = exports.catchIf = exports.catchAllDefect = exports.catchAllCause = exports.catchAll = exports.catch = exports.cachedWithTTL = exports.cachedInvalidateWithTTL = exports.cachedFunction = exports.cached = exports.cacheRequestResult = exports.blocked = exports.bindTo = exports.bindAll = exports.bind = exports.awaitAllChildren = exports.asyncEffect = exports.async = exports.asVoid = exports.asSomeError = exports.asSome = exports.as = exports.ap = exports.annotateSpans = exports.annotateLogsScoped = exports.annotateLogs = exports.annotateCurrentSpan = exports.andThen = exports.allowInterrupt = exports.allWith = exports.allSuccesses = exports.all = exports.addFinalizer = exports.acquireUseRelease = exports.acquireReleaseInterruptible = exports.acquireRelease = exports.Tag = exports.Service = exports.EffectTypeId = exports.Do = void 0;
exports.repeatOrElse = exports.repeatN = exports.repeat = exports.reduceWhile = exports.reduceRight = exports.reduceEffect = exports.reduce = exports.randomWith = exports.random = exports.raceWith = exports.raceFirst = exports.raceAll = exports.race = exports.provideServiceEffect = exports.provideService = exports.provide = exports.promise = exports.patchRuntimeFlags = exports.patchFiberRefs = exports.partition = exports.parallelFinalizers = exports.parallelErrors = exports.orElseSucceed = exports.orElseFail = exports.orElse = exports.orDieWith = exports.orDie = exports.optionFromOptional = exports.option = exports.once = exports.onInterrupt = exports.onExit = exports.onError = exports.none = exports.never = exports.negate = exports.metricLabels = exports.mergeAll = exports.merge = exports.matchEffect = exports.matchCauseEffect = exports.matchCause = exports.match = exports.mapInputContext = exports.mapErrorCause = exports.mapError = exports.mapBoth = exports.mapAccum = exports.map = exports.makeSpanScoped = exports.makeSpan = exports.makeSemaphore = exports.makeLatch = exports.loop = exports.logWithLevel = exports.logWarning = exports.logTrace = exports.logInfo = exports.logFatal = exports.logError = exports.logDebug = exports.logAnnotations = exports.log = exports.locallyWith = exports.locallyScopedWith = exports.locallyScoped = exports.locally = exports.linkSpans = exports.liftPredicate = exports.let = exports.labelMetricsScoped = exports.labelMetrics = exports.iterate = exports.isSuccess = exports.isFailure = exports.isEffect = exports.intoDeferred = exports.interruptibleMask = exports.interruptible = exports.interruptWith = exports.interrupt = exports.inheritFiberRefs = exports.ignoreLogged = exports.ignore = exports.if = exports.head = exports.getRuntimeFlags = exports.getFiberRefs = exports.gen = exports.functionWithSpan = exports.fromNullable = exports.fromFiberEffect = exports.fromFiber = exports.forkWithErrorHandler = exports.forkScoped = exports.forkIn = exports.forkDaemon = exports.forkAll = exports.fork = exports.forever = void 0;
exports.withMetric = exports.withMaxOpsBeforeYield = exports.withLogSpan = exports.withFiberRuntime = exports.withEarlyRelease = exports.withConsoleScoped = exports.withConsole = exports.withConfigProviderScoped = exports.withConfigProvider = exports.withConcurrency = exports.withClockScoped = exports.withClock = exports.whileLoop = exports.whenRef = exports.whenLogLevel = exports.whenFiberRef = exports.whenEffect = exports.when = exports.void = exports.validateWith = exports.validateFirst = exports.validateAll = exports.validate = exports.using = exports.useSpan = exports.updateService = exports.updateFiberRefs = exports.unsandbox = exports.unsafeMakeSemaphore = exports.unsafeMakeLatch = exports.unlessEffect = exports.unless = exports.uninterruptibleMask = exports.uninterruptible = exports.tryPromise = exports.tryMapPromise = exports.tryMap = exports.try = exports.transposeOption = exports.transplant = exports.tracerWith = exports.tracer = exports.timeoutTo = exports.timeoutOption = exports.timeoutFailCause = exports.timeoutFail = exports.timeout = exports.timedWith = exports.timed = exports.tapErrorTag = exports.tapErrorCause = exports.tapError = exports.tapDefect = exports.tapBoth = exports.tap = exports.takeWhile = exports.takeUntil = exports.tagMetricsScoped = exports.tagMetrics = exports.sync = exports.suspend = exports.supervised = exports.summarized = exports.succeedSome = exports.succeedNone = exports.succeed = exports.step = exports.spanLinks = exports.spanAnnotations = exports.sleep = exports.setFiberRefs = exports.serviceOptional = exports.serviceOption = exports.serviceMembers = exports.serviceFunctions = exports.serviceFunctionEffect = exports.serviceFunction = exports.serviceConstants = exports.sequentialFinalizers = exports.scopedWith = exports.scoped = exports.scopeWith = exports.scope = exports.scheduleFrom = exports.scheduleForked = exports.schedule = exports.sandbox = exports.runtime = exports.runSyncExit = exports.runSync = exports.runRequestBlock = exports.runPromiseExit = exports.runPromise = exports.runFork = exports.runCallback = exports.retryOrElse = exports.retry = exports.request = exports.replicateEffect = exports.replicate = void 0;
exports.zipWith = exports.zipRight = exports.zipLeft = exports.zip = exports.yieldNow = exports.withUnhandledErrorLogLevel = exports.withTracerTiming = exports.withTracerScoped = exports.withTracerEnabled = exports.withTracer = exports.withSpanScoped = exports.withSpan = exports.withSchedulingPriority = exports.withScheduler = exports.withRuntimeFlagsPatchScoped = exports.withRuntimeFlagsPatch = exports.withRequestCaching = exports.withRequestCache = exports.withRequestBatching = exports.withRandomScoped = exports.withRandom = exports.withParentSpan = void 0;
var _Function = require("./Function.js");
var internalCause = _interopRequireWildcard(require("./internal/cause.js"));
var console_ = _interopRequireWildcard(require("./internal/console.js"));
var _context = require("./internal/context.js");
var effect = _interopRequireWildcard(require("./internal/core-effect.js"));
var core = _interopRequireWildcard(require("./internal/core.js"));
var defaultServices = _interopRequireWildcard(require("./internal/defaultServices.js"));
var circular = _interopRequireWildcard(require("./internal/effect/circular.js"));
var fiberRuntime = _interopRequireWildcard(require("./internal/fiberRuntime.js"));
var layer = _interopRequireWildcard(require("./internal/layer.js"));
var option_ = _interopRequireWildcard(require("./internal/option.js"));
var query = _interopRequireWildcard(require("./internal/query.js"));
var runtime_ = _interopRequireWildcard(require("./internal/runtime.js"));
var schedule_ = _interopRequireWildcard(require("./internal/schedule.js"));
var internalTracer = _interopRequireWildcard(require("./internal/tracer.js"));
var Request = _interopRequireWildcard(require("./Request.js"));
var Scheduler = _interopRequireWildcard(require("./Scheduler.js"));
var _Utils = require("./Utils.js");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
/**
* @since 2.0.0
* @category Symbols
*/
const EffectTypeId = exports.EffectTypeId = core.EffectTypeId;
/**
* 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
*/
const isEffect = exports.isEffect = 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.
*
* @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.
*
* @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
* ```
*
* @since 2.0.0
* @category Caching
*/
const cachedWithTTL = exports.cachedWithTTL = 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.
*
* @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.
*
* @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
* ```
*
* @since 2.0.0
* @category Caching
*/
const cachedInvalidateWithTTL = exports.cachedInvalidateWithTTL = 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.
*
* @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.
*
* @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
* ```
*
* @since 2.0.0
* @category Caching
*/
const cached = exports.cached = 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
*/
const cachedFunction = exports.cachedFunction = 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
*/
const once = exports.once = 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
* // ┌─── 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.
*
* @see {@link forEach} for iterating over elements and applying an effect.
* @see {@link allWith} for a data-last version of this function.
*
* @example
* ```ts
* // Title: Combining Effects in Tuples
* 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
* // Title: Combining Effects in Iterables
* 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
* // Title: Combining Effects in Structs
* 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
* // Title: Combining Effects in Records
* 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
* // Title: Short-Circuiting Behavior
* 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
* // Title: Collecting Results with `mode: "either"`
* 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
* //Example: Collecting Results with `mode: "validate"`
* 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' }
* // ]
* // }
* // }
*
* @since 2.0.0
* @category Collecting
*/
const all = exports.all = 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
*/
const allWith = exports.allWith = fiberRuntime.allWith;
/**
* 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
*/
const allSuccesses = exports.allSuccesses = 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.
*
* @see {@link dropWhile} for a similar function that drops elements while the
* predicate returns `true`.
*
* @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]
* ```
*
* @since 2.0.0
* @category Collecting
*/
const dropUntil = exports.dropUntil = 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.
*
* @see {@link dropUntil} for a similar function that drops elements until the
* predicate returns `true`.
*
* @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]
* ```
*
* @since 2.0.0
* @category Collecting
*/
const dropWhile = exports.dropWhile = effect.dropWhile;
/**
* Takes elements from a collection until the effectful predicate returns
* `true`.
*
* **Details**
*
* This function processes a collection of elements and uses an effectful
* predicate to decide when to stop taking elements. The elements are taken 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 resolves to a boolean.
*
* Once the predicate returns `true`, the remaining elements of the collection
* are discarded, and the function stops taking more elements.
*
* **Note**: The first element for which the predicate returns `true` is also
* included in the result.
*
* **When to Use**
*
* Use this function when you want to conditionally take elements from a
* collection based on a dynamic condition. For example, you may want to collect
* numbers from a list until a certain threshold is reached, or gather items
* until a specific condition is met.
*
* @see {@link takeWhile} for a similar function that takes elements while the
* predicate returns `true`.
*
* @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.takeUntil(numbers, predicate)
* console.log(result)
* })
*
* // Effect.runFork(program)
* // Output: [ 1, 2, 3, 4 ]
* ```
*
* @since 2.0.0
* @category Collecting
*/
const takeUntil = exports.takeUntil = effect.takeUntil;
/**
* Takes elements as long as the predicate returns `true`.
*
* **Details**
*
* This function processes a collection of elements and uses a predicate to
* decide whether to take 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 taken
* from the collection.
*
* Once the predicate returns `false`, the remaining elements are discarded.
*
* @see {@link takeUntil} for a similar function that takes elements until the predicate returns `true`.
*
* @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.takeWhile(numbers, predicate)
* console.log(result)
* })
*
* // Effect.runFork(program)
* // Output: [1, 2, 3]
* ```
*
* @since 2.0.0
* @category Collecting
*/
const takeWhile = exports.takeWhile = effect.takeWhile;
/**
* Determines whether all elements of the iterable satisfy the effectful
* predicate.
*
* **Details**
*
* This function checks whether every element in a given collection (an
* iterable) satisfies a condition defined by an effectful predicate.
*
* The predicate is a function that takes an element and its index, and it
* returns an effect that evaluates to a boolean.
*
* The function will process each element and return `true` if all elements
* satisfy the predicate; otherwise, it returns `false`.
*
* **When to Use**
*
* This function is useful when you need to verify that all items in a
* collection meet certain criteria, even when the evaluation of each item
* involves effects, such as asynchronous checks or complex computations.
*
* @see {@link exists} for a similar function that returns a boolean indicating
* whether **any** element satisfies the predicate.
*
* @example
* ```ts
* import { Effect } from "effect"
*
* const numbers = [2, 4, 6, 8]
* const predicate = (n: number, i: number) => Effect.succeed(n % 2 === 0)
*
* const program = Effect.gen(function*() {
* const allEven = yield* Effect.every(numbers, predicate)
* console.log(allEven)
* })
*
* // Effect.runFork(program)
* // Output: true
* ```
*
* @since 2.0.0
* @category Condition Checking
*/
const every = exports.every = effect.every;
/**
* Determines whether any element of the iterable satisfies the effectual
* predicate.
*
* **Details**
*
* This function checks whether any element in a given collection (an iterable)
* satisfies a condition defined by an effectful predicate.
*
* The predicate is a function that takes an element and its index, and it
* returns an effect that evaluates to a boolean.
*
* The function will process each element, and if any element satisfies the
* predicate (returns `true`), the function will immediately return `true`.
*
* If none of the elements satisfy the condition, it will return `false`.
*
* **When to Use**
*
* This function allows you to quickly check for a condition in a collection
* without having to manually iterate over it.
*
* @see {@link every} for a similar function that checks if **all** elements
* satisfy the predicate.
*
* @example
* ```ts
* import { Effect } from "effect"
*
* const numbers = [1, 2, 3, 4]
* const predicate = (n: number, i: number) => Effect.succeed(n > 2)
*
* const program = Effect.gen(function*() {
* const hasLargeNumber = yield* Effect.exists(numbers, predicate)
* console.log(hasLargeNumber)
* })
*
* // Effect.runFork(program)
* // Output: true
* ```
*
* @since 2.0.0
* @category Condition Checking
*/
const exists = exports.exists = fiberRuntime.exists;
/**
* Filters an iterable using the specified effectful predicate.
*
* **Details**
*
* This function filters a collection (an iterable) by applying an effectful
* predicate.
*
* The predicate is a function that takes an element and its index, and it
* returns an effect that evaluates to a boolean.
*
* The function processes each element in the collection and keeps only those
* that satisfy the condition defined by the predicate.
*
* **Options**
*
* You can also adjust the behavior with options such as concurrency, batching,
* or whether to negate the condition.
*
* **When to Use**
*
* This function allows you to selectively keep or remove elements based on a
* condition that may involve asynchronous or side-effect-causing operations.
*
* @example
* ```ts
* import { Effect } from "effect"
*
* const numbers = [1, 2, 3, 4, 5]
* const predicate = (n: number, i: number) => Effect.succeed(n % 2 === 0)
*
* const program = Effect.gen(function*() {
* const result = yield* Effect.filter(numbers, predicate)
* console.log(result)
* })
*
* // Effect.runFork(program)
* // Output: [2, 4]
* ```
*
* @since 2.0.0
* @category Filtering
*/
const filter = exports.filter = fiberRuntime.filter;
/**
* Filters and maps elements sequentially in one operation.
*
* This function processes each element one by one. It applies a function that
* returns an `Option` to each element. If the function returns `Some`, the
* element is kept; if it returns `None`, the element is removed. The operation
* is done sequentially for each element.
*
* @example
* ```ts
* import { Console, Effect, Option } from "effect"
*
* const task = (n: number) =>
* Effect.succeed(n).pipe(
* Effect.delay(1000 - (n * 100)),
* Effect.tap(Console.log(`task${n} done`))
* )
*
* const program = Effect.filterMap(
* [task(1), task(2), task(3), task(4)],
* (n) => n % 2 === 0 ? Option.some(n) : Option.none()
* )
*
* // Effect.runPromise(program).then(console.log)
* // Output:
* // task1 done
* // task2 done
* // task3 done
* // task4 done
* // [ 2, 4 ]
* ```
*
* @since 2.0.0
* @category Filtering
*/
const filterMap = exports.filterMap = effect.filterMap;
/**
* Returns the first element that satisfies the effectful predicate.
*
* **Details**
*
* This function processes a collection of elements and applies an effectful
* predicate to each element.
*
* The predicate is a function that takes an element and its index in the
* collection, and it returns an effect that evaluates to a boolean.
*
* The function stops as soon as it finds the first element for which the
* predicate returns `true` and returns that element wrapped in an `Option`.
*
* If no element satisfies the predicate, the result will be `None`.
*
* **When to Use**
*
* This function allows you to efficiently find an element that meets a specific
* condition, even when the evaluation involves effects like asynchronous
* operations or side effects.
*
* @example
* ```ts
* import { Effect } from "effect"
*
* const numbers = [1, 2, 3, 4, 5]
* const predicate = (n: number, i: number) => Effect.succeed(n > 3)
*
* const program = Effect.gen(function*() {
* const result = yield* Effect.findFirst(numbers, predicate)
* console.log(result)
* })
*
* // Effect.runFork(program)
* // Output: { _id: 'Option', _tag: 'Some', value: 4 }
* ```
*
* @since 2.0.0
* @category Collecting
*/
const findFirst = exports.findFirst = effect.findFirst;
/**
* Executes an effectful operation for each element in an `Iterable`.
*
* **Details**
*
* This function applies a provided operation to each element in the iterable,
* producing a new effect that returns an array of results.
*
* If any effect fails, the iteration stops immediately (short-circuiting), and
* the error is propagated.
*
* **Concurrency**
*
* The `concurrency` option controls how many operations are performed
* concurrently. By default, the operations are performed sequentially.
*
* **Discarding Results**
*
* If the `discard` option is set to `true`, the intermediate results are not
* collected, and the final result of the operation is `void`.
*
* @see {@link all} for combining multiple effects into one.
*
* @example
* ```ts
* // Title: Applying Effects to Iterable Elements
* import { Effect, Console } from "effect"
*
* const result = Effect.forEach([1, 2, 3, 4, 5], (n, index) =>
* Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2))
* )
*
* // Effect.runPromise(result).then(console.log)
* // Output:
* // Currently at index 0
* // Currently at index 1
* // Currently at index 2
* // Currently at index 3
* // Currently at index 4
* // [ 2, 4, 6, 8, 10 ]
* ```
*
* @example
* // Title: Using discard to Ignore Results
* import { Effect, Console } from "effect"
*
* // Apply effects but discard the results
* const result = Effect.forEach(
* [1, 2, 3, 4, 5],
* (n, index) =>
* Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2)),
* { discard: true }
* )
*
* // Effect.runPromise(result).then(console.log)
* // Output:
* // Currently at index 0
* // Currently at index 1
* // Currently at index 2
* // Currently at index 3
* // Currently at index 4
* // undefined
*
* @since 2.0.0
* @category Looping
*/
const forEach = exports.forEach = fiberRuntime.forEach;
/**
* Returns the first element of the iterable if the collection is non-empty, or
* fails with the error `NoSuchElementException` if the collection is empty.
*
* **When to Use**
*
* This function is useful when you need to retrieve the first item from a
* collection and want to handle the case where the collection might be empty
* without causing an unhandled exception.
*
* @example
* ```ts
* import { Effect } from "effect"
*
* // Simulate an async operation
* const fetchNumbers = Effect.succeed([1, 2, 3]).pipe(Effect.delay("100 millis"))
*
* const program = Effect.gen(function*() {
* const firstElement = yield* Effect.head(fetchNumbers)
* console.log(firstElement)
* })
*
* // Effect.runFork(program)
* // Output: 1
* ```
*
* @since 2.0.0
* @category Collecting
*/
const head = exports.head = effect.head;
/**
* Merges an `Iterable<Effect<A, E, R>>` to a single effect.
*
* **Details**
*
* This function takes an iterable of effects and combines them into a single
* effect. It does this by iterating over each effect in the collection and
* applying a function that accumulates results into a "zero" value, which
* starts with an initial value and is updated with each effect's success.
*
* The provided function `f` is called for each element in the iterable,
* allowing you to specify how to combine the results.
*
* **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 numbers = [Effect.succeed(1), Effect.succeed(2), Effect.succeed(3)]
* const add = (sum: number, value: number, i: number) => sum + value
* const zero = 0
*
* const program = Effect.gen(function*() {
* const total = yield* Effect.mergeAll(numbers, zero, add)
* console.log(total)
* })
*
* // Effect.runFork(program)
* // Output: 6
* ```
*
* @since 2.0.0
* @category Collecting
*/
const mergeAll = exports.mergeAll = fiberRuntime.mergeAll;
/**
* Processes an iterable and applies an effectful function to each element,
* categorizing the results into successes and failures.
*
* **Details**
*
* This function processes each element in the provided iterable by applying an
* effectful function to it. The results are then categorized into two separate
* lists: one for failures and another for successes. This separation allows you
* to handle the two categories differently. Failures are collected in a list
* without interrupting the processing of the remaining elements, so the
* operation continues even if some elements fail. This is particularly useful
* when you need to handle both successful and failed results separately,
* without stopping the entire process on encountering a failure.
*
* **When to Use**
*
* Use this function when you want to process a collection of items and handle
* errors or failures without interrupting the processing of other items. It's
* useful when you need to distinguish between successful and failed results and
* process them separately, for example, when logging errors while continuing to
* work with valid data. The function ensures that failures are captured, while
* successes are processed normally.
*
* @see {@link validateAll} for a function that either collects all failures or all successes.
* @see {@link validateFirst} for a function that stops at the first success.
*
* @example
* ```ts
* import { Effect } from "effect"
*
* // ┌─── Effect<[string[], number[]], never, never>
* // ▼
* const program = Effect.partition([0, 1, 2, 3, 4], (n) => {
* if (n % 2 === 0) {
* return Effect.succeed(n)
* } else {
* return Effect.fail(`${n} is not even`)
* }
* })
*
* // Effect.runPromise(program).then(console.log, console.error)
* // Output:
* // [ [ '1 is not even', '3 is not even' ], [ 0, 2, 4 ] ]
* ```
*
* @since 2.0.0
* @category Error Accumulation
*/
const partition = exports.partition = fiberRuntime.partition;
/**
* Reduces an `Iterable<A>` using an effectual function `f`, working
* sequentially from left to right.
*
* **Details**
*
* This function takes an iterable and applies a function `f` to each element in
* the iterable. The function works sequentially, starting with an initial value
* `zero` and then combining it with each element in the collection. The
* provided function `f` is called for each element in the iterable, allowing
* you to accumulate a result based on the current value and the element being
* processed.
*
* **When to Use**
*
* The function is often used for operations like summing a collection of
* numbers or combining results from multiple tasks. It ensures that operations
* are performed one after the other, maintaining the order of the elements.
*
* @see {@link reduceWhile} for a similar function that stops the process based on a predicate.
* @see {@link reduceRight} for a similar function that works from right to left.
*
* @example
* ```ts
* import { Console, Effect } from "effect"
*
* const processOrder = (id: number) =>
* Effect.succeed({ id, price: 100 * id })
* .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100)))
*
* const program = Effect.reduce(
* [1, 2, 3, 4],
* 0,
* (acc, id, i) =>
* processOrder(id)
* .pipe(Effect.map((order) => acc + order.price))
* )
*
* // Effect.runPromise(program).then(console.log)
* // Output:
* // Order 1 processed
* // Order 2 processed
* // Order 3 processed
* // Order 4 processed
* // 1000
* ```
*
* @since 2.0.0
* @category Collecting
*/
const reduce = exports.reduce = effect.reduce;
/**
* Reduces an `Iterable<A>` using an effectual function `body`, working
* sequentially from left to right, stopping the process early when the
* predicate `while` is not satisfied.
*
* **Details**
*
* This function processes a collection of elements, applying a function `body`
* to reduce them to a single value, starting from the first element. It checks
* the value of the accumulator against a predicate (`while`). If at any point
* the predicate returns `false`, the reduction stops, and the accumulated
* result is returned.
*
* **When to Use**
*
* Use this function when you need to reduce a collection of elements, but only
* continue the process as long as a certain condition holds true. For example,
* if you want to sum values in a list but stop as soon as the sum exceeds a
* certain threshold, you can use this function.
*
* @example
* ```ts
* import { Console, Effect } from "effect"
*
* const processOrder = (id: number) =>
* Effect.succeed({ id, price: 100 * id })
* .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100)))
*
* const program = Effect.reduceWhile(
* [1, 2, 3, 4],
* 0,
* {
* body: (acc, id, i) =>
* processOrder(id)
* .pipe(Effect.map((order) => acc + order.price)),
* while: (acc) => acc < 500
* }
* )
*
* // Effect.runPromise(program).then(console.log)
* // Output:
* // Order 1 processed
* // Order 2 processed
* // Order 3 processed
* // 600
* ```
*
* @since 2.0.0
* @category Collecting
*/
const reduceWhile = exports.reduceWhile = effect.reduceWhile;
/**
* Reduces an `Iterable<A>` using an effectual function `f`, working
* sequentially from right to left.
*
* **Details**
*
* This function takes an iterable and applies a function `f` to each element in
* the iterable. The function works sequentially, starting with an initial value
* `zero` and then combining it with each element in the collection. The
* provided function `f` is called for each element in the iterable, allowing
* you to accumulate a result based on the current value and the element being
* processed.
*
* **When to Use**
*
* The function is often used for operations like summing a collection of
* numbers or combining results from multiple tasks. It ensures that operations
* are performed one after the other, maintaining the order of the elements.
*
* @see {@link reduce} for a similar function that works from left to right.
*
* @example
* ```ts
* import { Console, Effect } from "effect"
*
* const processOrder = (id: number) =>
* Effect.succeed({ id, price: 100 * id })
* .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100)))
*
* const program = Effect.reduceRight(
* [1, 2, 3, 4],
* 0,
* (id, acc, i) =>
* processOrder(id)
*