Matching
On this page
In the Effect
data type, just like other data types such as Option
and Exit
, we have a match
function that allows us to handle different cases simultaneously. When working with effects, we also have several functions that enable us to handle both success and failure scenarios.
match
The Effect.match
function allows us to handle both success and failure cases in a non-effectful manner by providing a handler for each case:
ts
import {Effect } from "effect"constsuccess :Effect .Effect <number,Error > =Effect .succeed (42)constfailure :Effect .Effect <number,Error > =Effect .fail (newError ("Uh oh!"))constprogram1 =Effect .match (success , {onFailure : (error ) => `failure: ${error .message }`,onSuccess : (value ) => `success: ${value }`})Effect .runPromise (program1 ).then (console .log ) // Output: "success: 42"constprogram2 =Effect .match (failure , {onFailure : (error ) => `failure: ${error .message }`,onSuccess : (value ) => `success: ${value }`})Effect .runPromise (program2 ).then (console .log ) // Output: "failure: Uh oh!"
ts
import {Effect } from "effect"constsuccess :Effect .Effect <number,Error > =Effect .succeed (42)constfailure :Effect .Effect <number,Error > =Effect .fail (newError ("Uh oh!"))constprogram1 =Effect .match (success , {onFailure : (error ) => `failure: ${error .message }`,onSuccess : (value ) => `success: ${value }`})Effect .runPromise (program1 ).then (console .log ) // Output: "success: 42"constprogram2 =Effect .match (failure , {onFailure : (error ) => `failure: ${error .message }`,onSuccess : (value ) => `success: ${value }`})Effect .runPromise (program2 ).then (console .log ) // Output: "failure: Uh oh!"
We can also choose to ignore the success and failure values if we're not interested in them:
ts
import {Effect } from "effect"import {constVoid } from "effect/Function"consttask =Effect .fail ("Uh oh!").pipe (Effect .as (5))constprogram =Effect .match (task , {onFailure :constVoid ,onSuccess :constVoid })
ts
import {Effect } from "effect"import {constVoid } from "effect/Function"consttask =Effect .fail ("Uh oh!").pipe (Effect .as (5))constprogram =Effect .match (task , {onFailure :constVoid ,onSuccess :constVoid })
In this case, we use the constVoid
function from the Function
module, which constantly returns void
, to provide handlers that perform no operation. This effectively discards the success and failure values and focuses solely on the control flow or side effects of the program. Alternatively, we can achieve the same result using the Effect.ignore
function:
ts
import {Effect } from "effect"consttask =Effect .fail ("Uh oh!").pipe (Effect .as (5))constprogram =Effect .ignore (task )
ts
import {Effect } from "effect"consttask =Effect .fail ("Uh oh!").pipe (Effect .as (5))constprogram =Effect .ignore (task )
matchEffect
In addition to Effect.match
, we have the Effect.matchEffect
function, which allows us to handle success and failure cases while performing additional side effects. Let's see an example:
ts
import {Effect } from "effect"constsuccess :Effect .Effect <number,Error > =Effect .succeed (42)constfailure :Effect .Effect <number,Error > =Effect .fail (newError ("Uh oh!"))constprogram1 =Effect .matchEffect (success , {onFailure : (error ) =>Effect .succeed (`failure: ${error .message }`).pipe (Effect .tap (Effect .log )),onSuccess : (value ) =>Effect .succeed (`success: ${value }`).pipe (Effect .tap (Effect .log ))})console .log (Effect .runSync (program1 ))/*Output:... message="success: 42"success: 42*/constprogram2 =Effect .matchEffect (failure , {onFailure : (error ) =>Effect .succeed (`failure: ${error .message }`).pipe (Effect .tap (Effect .log )),onSuccess : (value ) =>Effect .succeed (`success: ${value }`).pipe (Effect .tap (Effect .log ))})console .log (Effect .runSync (program2 ))/*Output:... message="failure: Uh oh!"failure: Uh oh!*/
ts
import {Effect } from "effect"constsuccess :Effect .Effect <number,Error > =Effect .succeed (42)constfailure :Effect .Effect <number,Error > =Effect .fail (newError ("Uh oh!"))constprogram1 =Effect .matchEffect (success , {onFailure : (error ) =>Effect .succeed (`failure: ${error .message }`).pipe (Effect .tap (Effect .log )),onSuccess : (value ) =>Effect .succeed (`success: ${value }`).pipe (Effect .tap (Effect .log ))})console .log (Effect .runSync (program1 ))/*Output:... message="success: 42"success: 42*/constprogram2 =Effect .matchEffect (failure , {onFailure : (error ) =>Effect .succeed (`failure: ${error .message }`).pipe (Effect .tap (Effect .log )),onSuccess : (value ) =>Effect .succeed (`success: ${value }`).pipe (Effect .tap (Effect .log ))})console .log (Effect .runSync (program2 ))/*Output:... message="failure: Uh oh!"failure: Uh oh!*/
In this example, we use Effect.matchEffect
instead of Effect.match
. The Effect.matchEffect
function allows us to perform additional side effects while handling success and failure cases. We can log messages or perform other side effects within the respective handlers.
matchCause / matchCauseEffect
Effect also provides Effect.matchCause
and Effect.matchCauseEffect
functions, which are useful for accessing the full cause of the underlying fiber in case of failure. This allows us to handle different failure causes separately and take appropriate actions. Here's an example:
ts
import {Effect ,Console } from "effect"declare constexceptionalEffect :Effect .Effect <void,Error >constprogram =Effect .matchCauseEffect (exceptionalEffect , {onFailure : (cause ) => {switch (cause ._tag ) {case "Fail":returnConsole .log (`Fail: ${cause .error .message }`)case "Die":returnConsole .log (`Die: ${cause .defect }`)case "Interrupt":returnConsole .log (`${cause .fiberId } interrupted!`)}returnConsole .log ("failed due to other causes")},onSuccess : (value ) =>Console .log (`succeeded with ${value } value`)})
ts
import {Effect ,Console } from "effect"declare constexceptionalEffect :Effect .Effect <void,Error >constprogram =Effect .matchCauseEffect (exceptionalEffect , {onFailure : (cause ) => {switch (cause ._tag ) {case "Fail":returnConsole .log (`Fail: ${cause .error .message }`)case "Die":returnConsole .log (`Die: ${cause .defect }`)case "Interrupt":returnConsole .log (`${cause .fiberId } interrupted!`)}returnConsole .log ("failed due to other causes")},onSuccess : (value ) =>Console .log (`succeeded with ${value } value`)})
In this example, we have an exceptionalEffect
that may fail or encounter other types of exceptions. The matchCauseEffect
function allows us to match and handle different failure causes separately.