# Matching

Catching errors recovers a *failure* back into the success channel. Sometimes
you instead want to handle *both* outcomes symmetrically — turning an
`Effect<A, E>` into an `Effect<B>` that can no longer fail by folding success and
failure into a single result type. That's what the `match` family does.

```ts
import { Effect } from "effect"

const success: Effect.Effect<number, Error> = Effect.succeed(42)
const failure: Effect.Effect<number, Error> = Effect.fail(new Error("Uh oh!"))

// Provide a handler for each channel. The result can no longer fail.
//      ┌─── Effect<string, never>
//      ▼
const describe = (effect: Effect.Effect<number, Error>) =>
  Effect.match(effect, {
    onFailure: (error) => `failure: ${error.message}`,
    onSuccess: (value) => `success: ${value}`
  })

Effect.runPromise(describe(success)).then(console.log) // "success: 42"
Effect.runPromise(describe(failure)).then(console.log) // "failure: Uh oh!"
```

## match — pure handlers

`Effect.match` takes `onSuccess` and `onFailure` handlers that return plain
values. The typed error is consumed, so the resulting effect's error channel
becomes `never`.
**Note:** `match` only sees *typed failures*. Defects and interruptions bypass it and
  remain in the cause. Use [`matchCause`](#matchcause--fold-the-full-cause) when
  you need to handle those too.

## matchEffect — effectful handlers

When the handlers themselves need to run effects — logging, notifying, writing a
fallback to a store — use `Effect.matchEffect`. Each handler returns an `Effect`
instead of a bare value.

```ts
import { Effect, Schema } from "effect"

class PaymentError extends Schema.TaggedErrorClass<PaymentError>()(
  "PaymentError",
  { reason: Schema.String }
) {}

declare const charge: Effect.Effect<number, PaymentError>

const program = charge.pipe(
  Effect.matchEffect({
    onFailure: (error) =>
      // Log the failure, then settle on a value.
      Effect.log(`charge failed: ${error.reason}`).pipe(Effect.as("declined")),
    onSuccess: (amount) =>
      Effect.log(`charged ${amount}`).pipe(Effect.as("approved"))
  })
)
// program: Effect<string, never>
```

## matchCause — fold the full cause

`Effect.matchCause` gives the failure handler the entire
[`Cause`](https://effect.plants.sh/error-management/result-and-exit/) rather than just the typed error.
A `Cause` is a *collection of reasons* — typed failures, defects, and
interruptions — so this is how you distinguish a defect from an expected error.

```ts
import { Cause, Effect } from "effect"

// `Effect.die` produces a defect, which a plain `match` would not catch.
const task: Effect.Effect<number, Error> = Effect.die("Uh oh!")

const program = Effect.matchCause(task, {
  onFailure: (cause) => {
    // Cause helpers let you ask what kind of reasons it contains.
    if (Cause.hasDies(cause)) return "stopped by a defect"
    if (Cause.hasInterrupts(cause)) return "interrupted"
    // Otherwise pull out the first typed failure, if any.
    const error = Cause.findErrorOption(cause)
    return error._tag === "Some" ? `failed: ${error.value}` : "unknown failure"
  },
  onSuccess: (value) => `succeeded with ${value}`
})

Effect.runPromise(program).then(console.log) // "stopped by a defect"
```

The companion `Effect.matchCauseEffect` is the same, but its handlers return
effects — combine cause inspection with logging or other side effects.

```ts
import { Cause, Effect } from "effect"

const task: Effect.Effect<number, Error> = Effect.die("boom")

const program = Effect.matchCauseEffect(task, {
  onFailure: (cause) =>
    // `Cause.pretty` renders the whole cause for diagnostics.
    Effect.logError(Cause.pretty(cause)).pipe(Effect.as("handled")),
  onSuccess: (value) => Effect.succeed(`ok: ${value}`)
})
```

## Choosing between catch and match

- Use **`catch*`** when you want to *recover a failure into the success channel*
  and possibly keep failing with other errors.
- Use **`match*`** when you want to *collapse both channels* into one result
  type that no longer fails.
- Use **`matchCause*`** when the distinction between failures, defects, and
  interruptions matters.

## Next steps

- Inspect outcomes as plain values with
  [Result & Exit](https://effect.plants.sh/error-management/result-and-exit/).
- Recover selectively with [Catching Errors](https://effect.plants.sh/error-management/catching-errors/).