# Function utilities

The `Function` module provides the small, pure helpers that make Effect's APIs
ergonomic. It backs the data-first/data-last call style used across the whole
library, the pipeline operators (`pipe`, `flow`, `compose`), and a handful of
identity, constant, and escape-hatch utilities.

Most of these are imported either as named exports from `effect` (the most
common ones: `pipe`, `flow`, `identity`, `absurd`, `hole`) or via the namespace:

```ts
import { Function, pipe, flow, identity } from "effect"
```

## The common case: `pipe` and `flow`

`pipe` and `flow` are two halves of the same idea — feeding a value through a
left-to-right sequence of unary functions.

- **`pipe`** starts with a *value* and applies functions to it immediately,
  returning the final result.
- **`flow`** composes the functions into a *new function* that you can call
  later.

```ts
import { pipe, flow } from "effect"

// `pipe`: apply a value through functions, get the result now
const result = pipe(
  5,
  (n) => n + 1, // 6
  (n) => n * 2, // 12
  (n) => `value: ${n}`
)
// => "value: 12"

// `flow`: compose the same steps into a reusable function
const transform = flow(
  (n: number) => n + 1,
  (n) => n * 2,
  (n) => `value: ${n}`
)

transform(5) // => "value: 12"
transform(9) // => "value: 20"
```

In short: `pipe(x, f, g)` is `g(f(x))`, while `flow(f, g)` is `(x) => g(f(x))`.
Each step after the first must be **unary** (accept a single argument), because
each function is called with only the previous step's result. `flow` is the only
one whose *first* function may take multiple arguments.

### `pipe` is also a method

Every Effect data type (and most pipeable values) carries a `.pipe` method, so
you rarely const a = pipe(
  Effect.succeed(1),
  Effect.map((n) => n + 1)
)

const b = Effect.succeed(1).pipe(
  Effect.map((n) => n + 1)
)
```

Use the free `pipe` function when the starting value is a plain JS value (like a
number or array) that has no `.pipe` method.

### Why data-last? `dual` in one paragraph

The functions you pass to `pipe`/`flow` are *data-last*: the value being
operated on is supplied last (e.g. `Array.map(double)` returns a function still
waiting for the array). Effect's combinators are built with [`dual`](#dual) so
they work **both** ways — `Array.map(xs, double)` (data-first) and
`pipe(xs, Array.map(double))` (data-last). If you are building your own
dual API, see the dedicated guide at [/code-style/dual-apis/](https://effect.plants.sh/code-style/dual-apis/);
the reference for `dual` itself is [below](#dual).

---

## Reference

### `pipe`

Applies an initial value through a left-to-right sequence of unary functions and
returns the final result. Equivalent to nested application.

```ts
pipe(5, (n) => n + 1, (n) => n * 2)
// => 12
```

### `flow`

Composes a left-to-right sequence of functions into a single reusable function.
The first function may have any arity; every following function must be unary.

```ts
const lenThenDouble = flow(
  (s: string) => s.length,
  (n) => n * 2
)

lenThenDouble("aaa")
// => 6
```

### `compose`

Composes exactly two unary functions into one. `compose(ab, bc)` produces
`(a) => bc(ab(a))`. It is `dual`, so it also reads data-last in a pipe.

```ts
const increment = (n: number) => n + 1
const square = (n: number) => n * n

Function.compose(increment, square)(2)
// => 9 (square(increment(2)) = square(3))
```

### `apply`

Applies a fixed value to a unary function: `apply(a)(f)` is `f(a)`. Handy when
the *function* is the value flowing through a pipe.

```ts
pipe(String.length, Function.apply("hello"))
// => 5
```

### `dual`

Builds a function callable in both data-first and data-last (`pipe`-friendly)
style from a single implementation. Pass either the **arity** of the
data-first form (the common case) or a **predicate** over the arguments when
optional parameters make arity ambiguous.

```ts
// data-first arity is 2: (self, that)
const sum = Function.dual<
  (that: number) => (self: number) => number, // data-last signature
  (self: number, that: number) => number // data-first signature
>(2, (self, that) => self + that)

sum(2, 3) // => 5  (data-first)
pipe(2, sum(3)) // => 5  (data-last)
```

Use a predicate instead of an arity when optional arguments mean the call count
alone cannot distinguish the two forms:

```ts
const sum = Function.dual<
  (that: number) => (self: number) => number,
  (self: number, that: number) => number
>(
  (args) => args.length === 2, // data-first when both args are present
  (self, that) => self + that
)

sum(2, 3) // => 5
pipe(2, sum(3)) // => 5
```

See [/code-style/dual-apis/](https://effect.plants.sh/code-style/dual-apis/) for the full guide on
authoring dual APIs.

### `flip`

Reverses the two argument groups of a curried function: `f(a)(b)` becomes
`flip(f)(b)(a)`.

```ts
const f = (a: number) => (b: string) => a - b.length

Function.flip(f)("aaa")(2)
// => -1  (original: f(2)("aaa") = 2 - 3)
```

### `tupled`

Adapts a multi-argument function so it accepts a single tuple argument instead.

```ts
const sumTupled = Function.tupled((x: number, y: number) => x + y)

sumTupled([1, 2])
// => 3
```

### `untupled`

The inverse of `tupled`: adapts a function that takes one tuple back into a
multi-argument function.

```ts
const getFirst = Function.untupled(<A, B>(tuple: [A, B]): A => tuple[0])

getFirst(1, 2)
// => 1
```

### `identity`

Returns its input unchanged. Useful wherever a function is required but no
transformation is wanted (e.g. a default mapping).

```ts
identity(5)
// => 5
```

### `constant`

Creates a zero-argument thunk that always returns the same provided value.

```ts
const always42 = Function.constant(42)

always42() // => 42
always42() // => 42
```

### `constTrue`

A thunk that always returns `true`. Equivalent to `constant(true)`.

```ts
Function.constTrue()
// => true
```

### `constFalse`

A thunk that always returns `false`.

```ts
Function.constFalse()
// => false
```

### `constNull`

A thunk that always returns `null`.

```ts
Function.constNull()
// => null
```

### `constUndefined`

A thunk that always returns `undefined`.

```ts
Function.constUndefined()
// => undefined
```

### `constVoid`

A thunk used only for its call effect, returning no meaningful value (it is an
alias of `constUndefined`).

```ts
Function.constVoid()
// => undefined
```

### `SK`

The SK combinator: takes two arguments and returns the **second**, discarding
the first.

```ts
Function.SK(0, "hello")
// => "hello"
```

### `satisfies`

A type-level check that an expression is assignable to a type **without**
widening or changing the expression's inferred type. The value is returned
unchanged at runtime.

```ts
const x = Function.satisfies<number>()(5 as const)
//    ^? const x: 5  (still narrowed to the literal 5)

// @ts-expect-error - 5 is not assignable to string
Function.satisfies<string>()(5)

x
// => 5
```

### `cast`

Returns the input value with a different static type. This is a **type-level
cast only** — it performs no runtime validation or conversion. Reach for it only
when you genuinely need to override the type checker.

```ts
const value: unknown = "hello"
const asString = Function.cast<unknown, string>(value)
//    ^? const asString: string  (no runtime change)

asString
// => "hello"
```

### `absurd`

Marks an unreachable branch. It accepts a value of type `never` and returns any
type, which is useful for exhaustiveness proofs. Because a `never` value should
never exist at runtime, **calling `absurd` throws**.

```ts
type Shape = { _tag: "circle" } | { _tag: "square" }

const area = (shape: Shape): number => {
  switch (shape._tag) {
    case "circle":
      return 1
    case "square":
      return 2
    default:
      // If a new variant is added, this line becomes a type error,
      // proving the switch is exhaustive.
      return absurd(shape)
  }
}

area({ _tag: "circle" })
// => 1
```

### `hole`

A compile-time placeholder of any type, for sketching incomplete code while
keeping the types happy. Like `absurd`, **evaluating `hole` at runtime throws**,
so it is strictly a development aid.

```ts
// Types check, but calling `buildUser` would throw at the `hole` call.
const buildUser = (id: number): { readonly id: number; readonly name: string } => ({
  id,
  name: hole<string>() // TODO: implement
})

typeof buildUser
// => "function"
```

### `LazyArg` (type)

The type of a zero-argument function that produces a value lazily —
`() => A`. Used to type thunks that should not run until called.

```ts
const lazyConfig: Function.LazyArg<{ readonly retries: number }> = () => ({
  retries: 3
})

lazyConfig()
// => { retries: 3 }
```

### `FunctionN` (type)

Describes a function whose argument list is given as a tuple type and whose
return type is `B`.

```ts
const sum: Function.FunctionN<[number, number], number> = (a, b) => a + b

sum(2, 3)
// => 5
```

### `FunctionTypeLambda` (type)

The higher-kinded type lambda for unary functions, used in advanced HKT-based
abstractions. You almost never reference this directly; it exists so generic
machinery can speak about `(a) => b` as a type constructor.

```ts
// Equivalent to `(a: string) => number`
type StringToNumber = HKT.Kind<
  Function.FunctionTypeLambda,
  string,
  never,
  never,
  number
>
```

### `memoize`

Wraps a function whose input is an **object**, caching results by object
identity using a private `WeakMap`. Subsequent calls with the *same reference*
return the cached result without recomputing.

```ts
let calls = 0
const expensive = Function.memoize((config: { id: number }) => {
  calls++
  return config.id * 2
})

const config = { id: 21 }

expensive(config) // => 42  (computed, calls === 1)
expensive(config) // => 42  (cached, calls still 1)

// A *different* object — even if structurally equal — is a cache miss:
expensive({ id: 21 }) // => 42  (recomputed, calls === 2)
```

Important caveats:

- The key must be an object (it is stored in a `WeakMap`). It is **not** a
  general-purpose cache for primitive values.
- Structurally equal objects do **not** share a cache entry — only identity
  matters.
- If an object is mutated after its first call, later calls still return the
  originally cached result for that reference.

For caching by value, with TTL, capacity limits, or effectful lookups, use the
[caching modules](https://effect.plants.sh/caching/) instead.