# Effect.fn

When you write a **function that returns an Effect**, use `Effect.fn("name")`.
It lets you use the generator syntax for the body, and in exchange for the name
you give it, it attaches a tracing span and improves stack traces - both
invaluable when debugging a real application. Avoid the common anti-pattern of
writing a plain function that returns `Effect.gen(...)`; `Effect.fn` is the
idiomatic replacement.

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

class SomeError extends Schema.TaggedErrorClass<SomeError>()("SomeError", {
  message: Schema.String
}) {}

// The string should match the function name. It becomes the span name and
// shows up in stack traces.
export const effectFunction = Effect.fn("effectFunction")(
  // `Effect.fn.Return<A, E>` documents the success and error types. It takes
  // the same type parameters as `Effect.Effect`.
  function*(n: number): Effect.fn.Return<string, SomeError> {
    yield* Effect.logInfo("Received number:", n)

    // Always `return` the yielded error so TypeScript knows execution stops.
    return yield* new SomeError({ message: "Failed to read the file" })
  },
  // Additional combinators are passed as extra arguments to Effect.fn -
  // do NOT use `.pipe` on an Effect.fn definition.
  Effect.catch((error) => Effect.logError(`An error occurred: ${error}`)),
  Effect.annotateLogs({ method: "effectFunction" })
)
```

## Why not a plain function returning `Effect.gen`?

These two look almost identical:

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

// Anti-pattern: a plain function returning Effect.gen.
const badGreet = (name: string) =>
  Effect.gen(function*() {
    yield* Effect.log(`Hello, ${name}`)
  })

// Idiomatic: Effect.fn with a name.
const greet = Effect.fn("greet")(function*(name: string) {
  yield* Effect.log(`Hello, ${name}`)
})
```

`greet` automatically wraps its body in a span called `"greet"` (as if you had
written `Effect.withSpan("greet")`) and records the call site for richer stack
traces. `badGreet` gets none of that. Since named functions are exactly the
boundaries you want to see in a trace, `Effect.fn` is the right default. See
[Observability](https://effect.plants.sh/observability/) for what those spans give you.

## Arguments and the generator body

The arguments you call the function with become the arguments of the generator.
Inside the body you write the same `yield*`-based code as in
[`Effect.gen`](https://effect.plants.sh/essentials/using-generators/):

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

const divide = Effect.fn("divide")(function*(a: number, b: number) {
  if (b === 0) {
    return yield* Effect.fail("Cannot divide by zero" as const)
  }
  return a / b
})

//      ┌─── Effect<number, "Cannot divide by zero">
//      ▼
const program = divide(10, 2)
```

## Adding behaviour with extra arguments

Anything you would normally `.pipe` onto an effect, you instead pass as extra
arguments after the generator. They are applied in order, wrapping the body:

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

const fetchPage = Effect.fn("fetchPage")(
  function*(url: string) {
    yield* Effect.log(`fetching ${url}`)
    return `<html>${url}</html>`
  },
  // Retry the whole body on failure, then add log annotations.
  Effect.retry({ times: 3 }),
  Effect.annotateLogs({ component: "fetchPage" })
)
```

This keeps the span, retry policy, and annotations together with the function
definition, which is exactly where you want them.

## `Effect.fnUntraced`

If you specifically do **not** want a span - for a hot, frequently-called
helper where the tracing overhead is unwelcome - use `Effect.fnUntraced`. It has
the same generator-based shape but skips the span and naming. Reach for it only
when you have a reason to; `Effect.fn("name")` is the better default.