In Effect you can perform various operations on the error channel of effects. These operations allow you to transform, inspect, and handle errors in different ways. Let’s explore some of these operations.
Map Operations
mapError
The Effect.mapError function is used when you need to transform or modify an error produced by an effect, without affecting the success value. This can be helpful when you want to add extra information to the error or change its type.
Example (Mapping an Error)
Here, the error type changes from string to Error.
mapBoth
The Effect.mapBoth function allows you to apply transformations to both channels: the error channel and the success channel of an effect. It takes two map functions as arguments: one for the error channel and the other for the success channel.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
The mapBoth function allows you to apply transformations to both the
error and success channels of an effect.
This function takes two map functions as arguments: one for the error channel
and one for the success channel. You can use it when you want to modify both
the error and the success values without altering the overall success or
failure status of the effect.
@see ― map for a version that operates on the success channel.
@see ― mapError for a version that operates on the error channel.
The Effect library provides several operators to filter values on the success channel based on a given predicate.
These operators offer different strategies for handling cases where the predicate fails:
API
Description
filterOrFail
This operator filters the values on the success channel based on a predicate. If the predicate fails for any value, the original effect fails with an error.
filterOrDie / filterOrDieMessage
These operators also filter the values on the success channel based on a predicate. If the predicate fails for any value, the original effect terminates abruptly. The filterOrDieMessage variant allows you to provide a custom error message.
filterOrElse
This operator filters the values on the success channel based on a predicate. If the predicate fails for any value, an alternative effect is executed instead.
Filter the specified effect with the provided function, failing with
specified error if the predicate fails.
In addition to the filtering capabilities discussed earlier, you have the
option to further refine and narrow down the type of the success channel by
providing a user-defined type
guard.
Let's explore this concept through an example:
@example
import { Effect, pipe } from"effect"
// Define a user interface
interfaceUser {
readonlyname:string
}
// Simulate an asynchronous authentication function
declareconstauth: () =>Promise<User|null>
constprogram=pipe(
Effect.promise(() =>auth()),
// Use filterOrFail with a custom type guard to ensure user is not null
Effect.filterOrFail(
(user):userisUser=> user !==null, // Type guard
() =>newError("Unauthorized")
),
// 'user' now has the type `User` (not `User | null`)
Returns the next numeric value in the specified range from the
pseudo-random number generator.
@since ― 2.0.0
nextRange(-1, 1),
27
(
n: number
n) =>
n: number
n>=0,
28
() =>
consttask3:Effect.Effect<number, never, never>
task3
29
)
It’s important to note that depending on the specific filtering operator used, the effect can either fail, terminate abruptly, or execute an alternative effect when the predicate fails. Choose the appropriate operator based on your desired error handling strategy and program logic.
The filtering APIs can also be combined with user-defined type guards to improve type safety and code clarity. This ensures that only valid types pass through.
Example (Using a Type Guard)
1
import {
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect,
functionpipe<A>(a:A):A (+19overloads)
Pipes the value of an expression into a pipeline of functions.
When to Use
This is useful in combination with data-last functions as a simulation of
methods:
as.map(f).filter(g)
becomes:
import { pipe, Array } from"effect"
pipe(as, Array.map(f), Array.filter(g))
Details
The pipe function is a utility that allows us to compose functions in a
readable and sequential manner. It takes the output of one function and
passes it as the input to the next function in the pipeline. This enables us
to build complex transformations by chaining multiple functions together.
import { pipe } from"effect"
constresult=pipe(input, func1, func2, ..., funcN)
In this syntax, input is the initial value, and func1, func2, ...,
funcN are the functions to be applied in sequence. The result of each
function becomes the input for the next function, and the final result is
returned.
Pipes the value of an expression into a pipeline of functions.
When to Use
This is useful in combination with data-last functions as a simulation of
methods:
as.map(f).filter(g)
becomes:
import { pipe, Array } from"effect"
pipe(as, Array.map(f), Array.filter(g))
Details
The pipe function is a utility that allows us to compose functions in a
readable and sequential manner. It takes the output of one function and
passes it as the input to the next function in the pipeline. This enables us
to build complex transformations by chaining multiple functions together.
import { pipe } from"effect"
constresult=pipe(input, func1, func2, ..., funcN)
In this syntax, input is the initial value, and func1, func2, ...,
funcN are the functions to be applied in sequence. The result of each
function becomes the input for the next function, and the final result is
returned.
Creates an Effect that represents an asynchronous computation guaranteed to
succeed.
When to Use
Use promise when you are sure the operation will not reject.
Details
The provided function (thunk) returns a Promise that should never reject; if it does, the error
will be treated as a "defect".
This defect is not a standard error but indicates a flaw in the logic that
was expected to be error-free. You can think of it similar to an unexpected
crash in the program, which can be further managed or logged using tools like
catchAllDefect
.
Interruptions
An optional AbortSignal can be provided to allow for interruption of the
wrapped Promise API.
@see ― tryPromise for a version that can handle failures.
Filter the specified effect with the provided function, failing with
specified error if the predicate fails.
In addition to the filtering capabilities discussed earlier, you have the
option to further refine and narrow down the type of the success channel by
providing a user-defined type
guard.
Let's explore this concept through an example:
@example
import { Effect, pipe } from"effect"
// Define a user interface
interfaceUser {
readonlyname:string
}
// Simulate an asynchronous authentication function
declareconstauth: () =>Promise<User|null>
constprogram=pipe(
Effect.promise(() =>auth()),
// Use filterOrFail with a custom type guard to ensure user is not null
Effect.filterOrFail(
(user):userisUser=> user !==null, // Type guard
() =>newError("Unauthorized")
),
// 'user' now has the type `User` (not `User | null`)
Effect.andThen((user) => user.name)
)
@since ― 2.0.0
filterOrFail(
15
(
user: User |null
user):
user: User |null
useris
interfaceUser
User=>
user: User |null
user!==null, // Type guard
16
() =>new
var Error:ErrorConstructor
new (message?:string) => Error
Error("Unauthorized")
17
),
18
// 'user' now has the type `User` (not `User | null`)
19
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect.
constandThen: <User, string>(f: (a:User) =>string) => <E, R>(self:Effect.Effect<User, E, R>) =>Effect.Effect<string, E, R> (+3overloads)
Chains two actions, where the second action can depend on the result of the
first.
Use andThen when you need to run multiple actions in sequence, with the
second action depending on the result of the first. This is useful for
combining effects or handling computations that must happen in order.
Details
The second action can be:
A constant value (similar to
as
)
A function returning a value (similar to
map
)
A Promise
A function returning a Promise
An Effect
A function returning an Effect (similar to
flatMap
)
Note:andThen works well with both Option and Either types,
treating them as effects.
@example
// Title: Applying a Discount Based on Fetched Amount
import { pipe, Effect } from"effect"
// Function to apply a discount safely to a transaction amount
constapplyDiscount= (
total:number,
discountRate:number
):Effect.Effect<number, Error> =>
discountRate ===0
? Effect.fail(newError("Discount rate cannot be zero"))
In the example above, a guard is used within the filterOrFail API to ensure that the user is of type User rather than User | null.
If you prefer, you can utilize a pre-made guard like Predicate.isNotNull for simplicity and consistency.
Inspecting Errors
Similar to tapping for success values, Effect provides several operators for inspecting error values.
These operators allow developers to observe failures or underlying issues without modifying the outcome.
tapError
Executes an effectful operation to inspect the failure of an effect without altering it.
Example (Inspecting Errors)
1
import {
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect,
import Console
Console } from"effect"
2
3
// Simulate a task that fails with an error
4
const
consttask:Effect.Effect<number, string, never>
task:
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect.
interfaceEffect<outA, outE=never, outR=never>
The Effect interface defines a value that lazily describes a workflow or
job. The workflow requires some context R, and may fail with an error of
type E, or succeed with a value of type A.
Effect values model resourceful interaction with the outside world,
including synchronous, asynchronous, concurrent, and parallel interaction.
They use a fiber-based concurrency model, with built-in support for
scheduling, fine-grained interruption, structured concurrency, and high
scalability.
To run an Effect value, you need a Runtime, which is a type that is
capable of executing Effect values.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
@example
// Title: Creating a Failed Effect
import { Effect } from"effect"
// ┌─── Effect<never, Error, never>
// ▼
constfailure= Effect.fail(
newError("Operation failed due to network error")
)
@since ― 2.0.0
fail("NetworkError")
5
6
// Use tapError to log the error message when the task fails
The tapError function executes an effectful operation to inspect the
failure of an effect without modifying it.
This function is useful when you want to perform some side effect (like
logging or tracking) on the failure of an effect, but without changing the
result of the effect itself. The error remains in the effect's error channel,
while the operation you provide can inspect or act on it.
The foundational function for running effects, returning a "fiber" that can
be observed or interrupted.
When to Use
runFork is used to run an effect in the background by creating a
fiber. It is the base function for all other run functions. It starts a fiber
that can be observed or interrupted.
Unless you specifically need a Promise or synchronous operation,
runFork is a good default choice.
The Effect interface defines a value that lazily describes a workflow or
job. The workflow requires some context R, and may fail with an error of
type E, or succeed with a value of type A.
Effect values model resourceful interaction with the outside world,
including synchronous, asynchronous, concurrent, and parallel interaction.
They use a fiber-based concurrency model, with built-in support for
scheduling, fine-grained interruption, structured concurrency, and high
scalability.
To run an Effect value, you need a Runtime, which is a type that is
capable of executing Effect values.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
The tapErrorTag function allows you to inspect errors that match a
specific tag, helping you handle different error types more precisely.
This function is useful when you want to target and act on specific error
types within an effect. You can use it to handle errors more granularly based
on their tags (e.g., inspecting only NetworkError or ValidationError),
without modifying the error or the overall result of the effect.
The foundational function for running effects, returning a "fiber" that can
be observed or interrupted.
When to Use
runFork is used to run an effect in the background by creating a
fiber. It is the base function for all other run functions. It starts a fiber
that can be observed or interrupted.
Unless you specifically need a Promise or synchronous operation,
runFork is a good default choice.
This function inspects the complete cause of an error, including failures and defects.
Example (Inspecting Error Causes)
1
import {
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect,
import Console
Console } from"effect"
2
3
// Create a task that fails with a NetworkError
4
const
consttask1:Effect.Effect<number, string, never>
task1:
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect.
interfaceEffect<outA, outE=never, outR=never>
The Effect interface defines a value that lazily describes a workflow or
job. The workflow requires some context R, and may fail with an error of
type E, or succeed with a value of type A.
Effect values model resourceful interaction with the outside world,
including synchronous, asynchronous, concurrent, and parallel interaction.
They use a fiber-based concurrency model, with built-in support for
scheduling, fine-grained interruption, structured concurrency, and high
scalability.
To run an Effect value, you need a Runtime, which is a type that is
capable of executing Effect values.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
The tapErrorCause function allows you to inspect the complete cause
of an error, including failures and defects.
This function is helpful when you need to log, monitor, or handle specific
error causes in your effects. It gives you access to the full error cause,
whether it’s a failure, defect, or other exceptional conditions, without
altering the error or the overall result of the effect.
The foundational function for running effects, returning a "fiber" that can
be observed or interrupted.
When to Use
runFork is used to run an effect in the background by creating a
fiber. It is the base function for all other run functions. It starts a fiber
that can be observed or interrupted.
Unless you specifically need a Promise or synchronous operation,
runFork is a good default choice.
The Effect interface defines a value that lazily describes a workflow or
job. The workflow requires some context R, and may fail with an error of
type E, or succeed with a value of type A.
Effect values model resourceful interaction with the outside world,
including synchronous, asynchronous, concurrent, and parallel interaction.
They use a fiber-based concurrency model, with built-in support for
scheduling, fine-grained interruption, structured concurrency, and high
scalability.
To run an Effect value, you need a Runtime, which is a type that is
capable of executing Effect values.
Creates an effect that terminates a fiber with a RuntimeException
containing the specified message.
When to Use
Use dieMessage when you want to terminate a fiber due to an unrecoverable
defect and include a clear explanation in the message.
Details
The dieMessage function is used to signal a defect, representing a critical
and unexpected error in the code. When invoked, it produces an effect that
terminates the fiber with a RuntimeException carrying the given message.
The resulting effect has an error channel of type never, indicating it does
not handle or recover from the error.
@see ― die for a variant that throws a specified error.
@see ― dieSync for a variant that throws a specified error, evaluated
lazily.
@example
// Title: Terminating on Division by Zero with a Specified Message
import { Effect } from"effect"
constdivide= (a:number, b:number) =>
b ===0
? Effect.dieMessage("Cannot divide by zero")
: Effect.succeed(a / b)
// ┌─── Effect<number, never, never>
// ▼
constprogram=divide(1, 0)
Effect.runPromise(program).catch(console.error)
// Output:
// (FiberFailure) RuntimeException: Cannot divide by zero
The tapErrorCause function allows you to inspect the complete cause
of an error, including failures and defects.
This function is helpful when you need to log, monitor, or handle specific
error causes in your effects. It gives you access to the full error cause,
whether it’s a failure, defect, or other exceptional conditions, without
altering the error or the overall result of the effect.
The foundational function for running effects, returning a "fiber" that can
be observed or interrupted.
When to Use
runFork is used to run an effect in the background by creating a
fiber. It is the base function for all other run functions. It starts a fiber
that can be observed or interrupted.
Unless you specifically need a Promise or synchronous operation,
runFork is a good default choice.
error cause: RuntimeException: Something went wrong
29
... stack trace ...
30
*/
tapDefect
Specifically inspects non-recoverable failures or defects in an effect (i.e., one or more Die causes).
Example (Inspecting Defects)
1
import {
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect,
import Console
Console } from"effect"
2
3
// Simulate a task that fails with a recoverable error
4
const
consttask1:Effect.Effect<number, string, never>
task1:
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect.
interfaceEffect<outA, outE=never, outR=never>
The Effect interface defines a value that lazily describes a workflow or
job. The workflow requires some context R, and may fail with an error of
type E, or succeed with a value of type A.
Effect values model resourceful interaction with the outside world,
including synchronous, asynchronous, concurrent, and parallel interaction.
They use a fiber-based concurrency model, with built-in support for
scheduling, fine-grained interruption, structured concurrency, and high
scalability.
To run an Effect value, you need a Runtime, which is a type that is
capable of executing Effect values.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
@example
// Title: Creating a Failed Effect
import { Effect } from"effect"
// ┌─── Effect<never, Error, never>
// ▼
constfailure= Effect.fail(
newError("Operation failed due to network error")
)
@since ― 2.0.0
fail("NetworkError")
5
6
// tapDefect won't log anything because NetworkError is not a defect
The tapDefect function specifically inspects non-recoverable
failures or defects (i.e., one or more Die causes) in an effect.
This function is designed to catch severe errors in your program that
represent critical issues, like system failures or unexpected errors
(defects). It helps you log or handle these defects without altering the main
result of the effect, allowing for efficient debugging or monitoring of
severe errors.
@example
import { Effect, Console } from"effect"
// Simulate a task that fails with a recoverable error
The foundational function for running effects, returning a "fiber" that can
be observed or interrupted.
When to Use
runFork is used to run an effect in the background by creating a
fiber. It is the base function for all other run functions. It starts a fiber
that can be observed or interrupted.
Unless you specifically need a Promise or synchronous operation,
runFork is a good default choice.
The Effect interface defines a value that lazily describes a workflow or
job. The workflow requires some context R, and may fail with an error of
type E, or succeed with a value of type A.
Effect values model resourceful interaction with the outside world,
including synchronous, asynchronous, concurrent, and parallel interaction.
They use a fiber-based concurrency model, with built-in support for
scheduling, fine-grained interruption, structured concurrency, and high
scalability.
To run an Effect value, you need a Runtime, which is a type that is
capable of executing Effect values.
Creates an effect that terminates a fiber with a RuntimeException
containing the specified message.
When to Use
Use dieMessage when you want to terminate a fiber due to an unrecoverable
defect and include a clear explanation in the message.
Details
The dieMessage function is used to signal a defect, representing a critical
and unexpected error in the code. When invoked, it produces an effect that
terminates the fiber with a RuntimeException carrying the given message.
The resulting effect has an error channel of type never, indicating it does
not handle or recover from the error.
@see ― die for a variant that throws a specified error.
@see ― dieSync for a variant that throws a specified error, evaluated
lazily.
@example
// Title: Terminating on Division by Zero with a Specified Message
import { Effect } from"effect"
constdivide= (a:number, b:number) =>
b ===0
? Effect.dieMessage("Cannot divide by zero")
: Effect.succeed(a / b)
// ┌─── Effect<number, never, never>
// ▼
constprogram=divide(1, 0)
Effect.runPromise(program).catch(console.error)
// Output:
// (FiberFailure) RuntimeException: Cannot divide by zero
The tapDefect function specifically inspects non-recoverable
failures or defects (i.e., one or more Die causes) in an effect.
This function is designed to catch severe errors in your program that
represent critical issues, like system failures or unexpected errors
(defects). It helps you log or handle these defects without altering the main
result of the effect, allowing for efficient debugging or monitoring of
severe errors.
@example
import { Effect, Console } from"effect"
// Simulate a task that fails with a recoverable error
The foundational function for running effects, returning a "fiber" that can
be observed or interrupted.
When to Use
runFork is used to run an effect in the background by creating a
fiber. It is the base function for all other run functions. It starts a fiber
that can be observed or interrupted.
Unless you specifically need a Promise or synchronous operation,
runFork is a good default choice.
Filter the specified effect with the provided function, failing with
specified error if the predicate fails.
In addition to the filtering capabilities discussed earlier, you have the
option to further refine and narrow down the type of the success channel by
providing a user-defined type
guard.
Let's explore this concept through an example:
@example
import { Effect, pipe } from"effect"
// Define a user interface
interfaceUser {
readonlyname:string
}
// Simulate an asynchronous authentication function
declareconstauth: () =>Promise<User|null>
constprogram=pipe(
Effect.promise(() =>auth()),
// Use filterOrFail with a custom type guard to ensure user is not null
Effect.filterOrFail(
(user):userisUser=> user !==null, // Type guard
() =>newError("Unauthorized")
),
// 'user' now has the type `User` (not `User | null`)
The tapBoth function allows you to inspect both the success and
failure outcomes of an effect, performing different actions based on the
result.
This function is useful when you need to handle both successful results and
failures separately, allowing for side effects such as logging, metrics
collection, or conditional actions based on whether the effect succeeded or
failed. It provides a way to react to the outcome of an effect without
altering the result.
@example
import { Effect, Random, Console } from"effect"
// Simulate a task that might fail
consttask= Effect.filterOrFail(
Random.nextRange(-1, 1),
(n) => n >=0,
() =>"random number is negative"
)
// Use tapBoth to log both success and failure outcomes
The foundational function for running effects, returning a "fiber" that can
be observed or interrupted.
When to Use
runFork is used to run an effect in the background by creating a
fiber. It is the base function for all other run functions. It starts a fiber
that can be observed or interrupted.
Unless you specifically need a Promise or synchronous operation,
runFork is a good default choice.
The Effect.either function transforms an Effect<A, E, R> into an effect that encapsulates both potential failure and success within an Either data type:
Effect<A, E, R>-> Effect<Either<A, E>, never, R>
This means if you have an effect with the following type:
Effect<string, HttpError, never>
and you call Effect.either on it, the type becomes:
Effect<Either<string, HttpError>, never, never>
The resulting effect cannot fail because the potential failure is now represented within the Either’s Left type.
The error type of the returned Effect is specified as never, confirming that the effect is structured to not fail.
This function becomes especially useful when recovering from effects that may fail when using Effect.gen:
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to Use
gen allows you to write code that looks and behaves like synchronous
code, but it can handle asynchronous tasks, errors, and complex control flow
(like loops and conditions). It helps make asynchronous code more readable
and easier to manage.
The generator functions work similarly to async/await but with more
explicit control over the execution of effects. You can yield* values from
effects and return the final result at the end.
Transforms an Effect into one that encapsulates both success and failure
using the Either data type.
Details
either takes an effect that could potentially fail and converts it
into an effect that always succeeds but with the result inside an Either.
The Either can either be a Left (representing failure) or a Right
(representing success). This allows you to handle both cases explicitly
without causing the effect to fail.
The resulting effect cannot fail because failure is now represented inside
the Either type.
@see ― option for a version that uses Option instead.
Executes an effect and returns the result as a Promise.
When to Use
Use runPromise when you need to execute an effect and work with the
result using Promise syntax, typically for compatibility with other
promise-based code.
If the effect succeeds, the promise will resolve with the result. If the
effect fails, the promise will reject with an error.
@see ― runPromiseExit for a version that returns an Exit type instead of rejecting.
@example
// Title: Running a Successful Effect as a Promise
Attaches callbacks for the resolution and/or rejection of the Promise.
@param ― onfulfilled The callback to execute when the Promise is resolved.
@param ― onrejected The callback to execute when the Promise is rejected.
@returns ― A Promise for the completion of which ever callback is executed.
then(
var console:Console
The console module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
A global console instance configured to write to process.stdout and
process.stderr. The global console can be used without importing the node:console module.
Warning: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the note on process I/O for
more information.
Example using the global console:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(newError('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
constname='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
constout=getStreamSomehow();
consterr=getStreamSomehow();
constmyConsole=new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
Prints to stdout with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()).
You can use the Effect.cause function to expose the cause of an effect, which is a more detailed representation of failures, including error messages and defects.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to Use
gen allows you to write code that looks and behaves like synchronous
code, but it can handle asynchronous tasks, errors, and complex control flow
(like loops and conditions). It helps make asynchronous code more readable
and easier to manage.
The generator functions work similarly to async/await but with more
explicit control over the execution of effects. You can yield* values from
effects and return the final result at the end.
The cause function allows you to expose the detailed cause of an
effect, which includes a more precise representation of failures, such as
error messages and defects.
This function is helpful when you need to inspect the cause of a failure in
an effect, giving you more information than just the error message. It can be
used to log, handle, or analyze failures in more detail, including
distinguishing between different types of defects (e.g., runtime exceptions,
interruptions, etc.).
Merging the Error Channel into the Success Channel
The Effect.merge function allows you to combine the error channel with the success channel. This results in an effect that never fails; instead, both successes and errors are handled as values in the success channel.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
The merge function combines both the error and success channels of
an effect, creating a new effect that never fails.
This function transforms an effect that may fail into one that always returns
a value, where both success and failure outcomes are handled as values in the
success channel. This can be useful when you want to continue execution
regardless of the error type and still capture both successful results and
errors as part of the outcome.
The Effect.flip function allows you to switch the error and success channels of an effect. This means that what was previously a success becomes the error, and vice versa.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
The flip function swaps the success and error channels of an effect,
so that the success becomes the error, and the error becomes the success.
This function is useful when you need to reverse the flow of an effect,
treating the previously successful values as errors and vice versa. This can
be helpful in scenarios where you want to handle a success as a failure or
treat an error as a valid result.