or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

algebraic.mdarray.mdeither.mdfunction.mdindex.mdio.mdoption.mdpipeable.mdrecord.mdtask-either.mdtask.mdtype-classes.md
tile.json

type-classes.mddocs/

Type Classes

Type classes in fp-ts provide generic operations that work across different data types. They enable higher-level abstractions and code reuse through polymorphism, similar to interfaces but more powerful.

Capabilities

Functor

Map functions over wrapped values, preserving structure.

interface Functor<F> {
  readonly map: <A, B>(fa: HKT<F, A>, f: (a: A) => B) => HKT<F, B>;
}

interface Functor1<F extends URIS> {
  readonly map: <A, B>(fa: Kind<F, A>, f: (a: A) => B) => Kind<F, B>;
}

interface Functor2<F extends URIS2> {
  readonly map: <L, A, B>(fa: Kind2<F, L, A>, f: (a: A) => B) => Kind2<F, L, B>;
}

Usage Examples:

import { map } from "fp-ts/lib/Option";
import { some, none } from "fp-ts/lib/Option";

// Map over Option
const doubled = map((n: number) => n * 2)(some(21)); // Some(42)
const stillNone = map((n: number) => n * 2)(none);   // None

Apply

Apply wrapped functions to wrapped values.

interface Apply<F> extends Functor<F> {
  readonly ap: <A, B>(fab: HKT<F, (a: A) => B>, fa: HKT<F, A>) => HKT<F, B>;
}

interface Apply1<F extends URIS> extends Functor1<F> {
  readonly ap: <A, B>(fab: Kind<F, (a: A) => B>, fa: Kind<F, A>) => Kind<F, B>;
}

interface Apply2<F extends URIS2> extends Functor2<F> {
  readonly ap: <L, A, B>(fab: Kind2<F, L, (a: A) => B>, fa: Kind2<F, L, A>) => Kind2<F, L, B>;
}

Applicative

Lift pure values into wrapped context, extending Apply.

interface Applicative<F> extends Apply<F> {
  readonly of: <A>(a: A) => HKT<F, A>;
}

interface Applicative1<F extends URIS> extends Apply1<F> {
  readonly of: <A>(a: A) => Kind<F, A>;
}

interface Applicative2<F extends URIS2> extends Apply2<F> {
  readonly of: <L, A>(a: A) => Kind2<F, L, A>;
}

Usage Examples:

import { sequenceS } from "fp-ts/lib/Apply";
import { option } from "fp-ts/lib/Option";
import { some, none } from "fp-ts/lib/Option";

// Combine multiple Options
const result = sequenceS(option)({
  name: some("Alice"),
  age: some(30),
  email: some("alice@example.com")
});
// Some({ name: "Alice", age: 30, email: "alice@example.com" })

// If any is None, result is None
const failed = sequenceS(option)({
  name: some("Bob"),
  age: none,
  email: some("bob@example.com")
});
// None

Chain

Sequential composition of wrapped computations (also known as flatMap).

interface Chain<F> extends Apply<F> {
  readonly chain: <A, B>(fa: HKT<F, A>, f: (a: A) => HKT<F, B>) => HKT<F, B>;
}

interface Chain1<F extends URIS> extends Apply1<F> {
  readonly chain: <A, B>(fa: Kind<F, A>, f: (a: A) => Kind<F, B>) => Kind<F, B>;
}

interface Chain2<F extends URIS2> extends Apply2<F> {
  readonly chain: <L, A, B>(fa: Kind2<F, L, A>, f: (a: A) => Kind2<F, L, B>) => Kind2<F, L, B>;
}

Monad

Combines Applicative and Chain, enabling full monadic operations.

interface Monad<F> extends Applicative<F>, Chain<F> {}

interface Monad1<F extends URIS> extends Applicative1<F>, Chain1<F> {}

interface Monad2<F extends URIS2> extends Applicative2<F>, Chain2<F> {}

Usage Examples:

import { chain, of } from "fp-ts/lib/Option";
import { some, none } from "fp-ts/lib/Option";

// Chain optional computations
const divide = (n: number) => (d: number) => 
  d === 0 ? none : some(n / d);

const result1 = chain(divide(10))(some(2)); // Some(5)
const result2 = chain(divide(10))(some(0)); // None
const result3 = chain(divide(10))(none);    // None

Foldable

Fold (reduce) structures to single values.

interface Foldable<F> {
  readonly reduce: <A, B>(fa: HKT<F, A>, b: B, f: (b: B, a: A) => B) => B;
  readonly foldMap: <M>(M: Monoid<M>) => <A>(fa: HKT<F, A>, f: (a: A) => M) => M;
  readonly reduceRight: <A, B>(fa: HKT<F, A>, b: B, f: (a: A, b: B) => B) => B;
}

interface Foldable1<F extends URIS> {
  readonly reduce: <A, B>(fa: Kind<F, A>, b: B, f: (b: B, a: A) => B) => B;
  readonly foldMap: <M>(M: Monoid<M>) => <A>(fa: Kind<F, A>, f: (a: A) => M) => M;
  readonly reduceRight: <A, B>(fa: Kind<F, A>, b: B, f: (a: A, b: B) => B) => B;
}

Usage Examples:

import { reduce, foldMap } from "fp-ts/lib/Array";
import { monoidSum } from "fp-ts/lib/Monoid";

// Reduce array to sum
const numbers = [1, 2, 3, 4, 5];
const sum = reduce(0, (acc: number, n: number) => acc + n)(numbers); // 15

// Fold with monoid
const total = foldMap(monoidSum)((n: number) => n)(numbers); // 15

Traversable

Traverse structures, applying effects while preserving shape.

interface Traversable<F> extends Functor<F>, Foldable<F> {
  readonly traverse: <G>(G: Applicative<G>) => <A, B>(ta: HKT<F, A>, f: (a: A) => HKT<G, B>) => HKT<G, HKT<F, B>>;
  readonly sequence: <G>(G: Applicative<G>) => <A>(tga: HKT<F, HKT<G, A>>) => HKT<G, HKT<F, A>>;
}

Usage Examples:

import { traverse } from "fp-ts/lib/Array";
import { option } from "fp-ts/lib/Option";
import { some, none } from "fp-ts/lib/Option";

// Transform array of numbers to array of Options, then sequence
const parseInts = (strings: string[]) => 
  traverse(option)(strings, (s: string) => {
    const n = parseInt(s, 10);
    return isNaN(n) ? none : some(n);
  });

const valid = parseInts(["1", "2", "3"]);    // Some([1, 2, 3])
const invalid = parseInts(["1", "a", "3"]);  // None

Semigroup

Associative binary operation for combining values.

interface Semigroup<A> {
  readonly concat: (x: A, y: A) => A;
}

Usage Examples:

import { semigroupSum, semigroupString } from "fp-ts/lib/Semigroup";

// Numeric addition
const sum = semigroupSum.concat(5, 10); // 15

// String concatenation
const greeting = semigroupString.concat("Hello", " World"); // "Hello World"

// Custom semigroup
const semigroupMax: Semigroup<number> = {
  concat: (x, y) => Math.max(x, y)
};
const maximum = semigroupMax.concat(3, 7); // 7

Monoid

Semigroup with identity element.

interface Monoid<A> extends Semigroup<A> {
  readonly empty: A;
}

Usage Examples:

import { monoidSum, monoidString, fold } from "fp-ts/lib/Monoid";

// Identity elements
const zeroSum = monoidSum.empty;     // 0
const emptyString = monoidString.empty; // ""

// Fold array with monoid
const numbers = [1, 2, 3, 4, 5];
const total = fold(monoidSum)(numbers); // 15

const words = ["Hello", " ", "World"];
const sentence = fold(monoidString)(words); // "Hello World"

Eq

Equality testing type class.

interface Eq<A> {
  readonly equals: (x: A, y: A) => boolean;
}

Usage Examples:

import { eqNumber, eqString, contramap } from "fp-ts/lib/Eq";

// Basic equality
const isEqual = eqNumber.equals(5, 5); // true
const notEqual = eqString.equals("a", "b"); // false

// Derive equality for complex types
interface Person {
  name: string;
  age: number;
}

const eqPerson: Eq<Person> = {
  equals: (x, y) => x.name === y.name && x.age === y.age
};

// Use contramap to derive from existing Eq
const eqPersonByName = contramap((p: Person) => p.name)(eqString);

Ord

Ordering/comparison type class.

interface Ord<A> extends Eq<A> {
  readonly compare: (x: A, y: A) => Ordering;
}

type Ordering = -1 | 0 | 1;

Usage Examples:

import { ordNumber, ordString, min, max, sort } from "fp-ts/lib/Ord";

// Comparison
const comparison = ordNumber.compare(5, 10); // -1 (less than)

// Min/max
const minimum = min(ordNumber)(3, 7); // 3
const maximum = max(ordString)("apple", "banana"); // "banana"

// Sort array
const numbers = [3, 1, 4, 1, 5];
const sorted = sort(ordNumber)(numbers); // [1, 1, 3, 4, 5]

Show

String representation type class.

interface Show<A> {
  readonly show: (a: A) => string;
}

Usage Examples:

import { showNumber, showString, showBoolean } from "fp-ts/lib/Show";

// Basic show instances
const numStr = showNumber.show(42);        // "42"
const strStr = showString.show("hello");   // "hello"
const boolStr = showBoolean.show(true);    // "true"

// Custom show instance
interface Person {
  name: string;
  age: number;
}

const showPerson: Show<Person> = {
  show: (p) => `${p.name} (${p.age})`
};

const personStr = showPerson.show({ name: "Alice", age: 30 }); // "Alice (30)"

Alternative

Choice between alternatives with identity.

interface Alternative<F> extends Applicative<F>, Plus<F> {}

interface Plus<F> extends Alt<F> {
  readonly zero: <A>() => HKT<F, A>;
}

interface Alt<F> extends Functor<F> {
  readonly alt: <A>(fx: HKT<F, A>, fy: Lazy<HKT<F, A>>) => HKT<F, A>;
}

Usage Examples:

import { alt } from "fp-ts/lib/Option";
import { some, none } from "fp-ts/lib/Option";

// Alternative choices
const first = alt(() => some("fallback"))(some("primary"));   // Some("primary")
const second = alt(() => some("fallback"))(none);             // Some("fallback")
const third = alt(() => none)(none);                          // None

Higher-Order Operations

Generic operations that work with any type class instance.

/**
 * Sequence array of wrapped values
 * @param A - Applicative instance
 * @returns Function that sequences array
 */
function sequenceArray<F extends URIS>(A: Applicative1<F>): <A>(arr: Array<Kind<F, A>>) => Kind<F, Array<A>>;

/**
 * Traverse array with effect
 * @param A - Applicative instance
 * @returns Function that traverses array
 */
function traverseArray<F extends URIS>(A: Applicative1<F>): <A, B>(f: (a: A) => Kind<F, B>) => (arr: Array<A>) => Kind<F, Array<B>>;

/**
 * Replicate wrapped value n times
 * @param A - Applicative instance
 * @returns Function that replicates value
 */
function replicateA<F extends URIS>(A: Applicative1<F>): <A>(n: number, fa: Kind<F, A>) => Kind<F, Array<A>>;