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

io.mddocs/

IO Operations

IO represents synchronous side-effectful computations that never fail. IO actions are lazy and only executed when the run() method is called, enabling controlled side effect management.

Capabilities

Core Construction

Create IO instances from values and functions.

/**
 * Create IO from pure value
 * @param a - Value to wrap in IO
 * @returns IO that returns the value when run
 */
function of<A>(a: A): IO<A>;

/**
 * Create IO from lazy computation
 * @param f - Function to execute
 * @returns IO that executes function when run
 */
function io<A>(f: Lazy<A>): IO<A>;

/**
 * Never-resolving IO (infinite computation)
 */
const never: IO<never>;

Usage Examples:

import { IO, of as ioOf } from "fp-ts/lib/IO";

// Pure value
const constantIO = ioOf(42);
const result1 = constantIO.run(); // 42

// Lazy computation
const randomIO = new IO(() => Math.random());
const result2 = randomIO.run(); // random number
const result3 = randomIO.run(); // different random number

// Side-effectful computation
const logIO = (message: string) => new IO(() => {
  console.log(message);
  return undefined;
});
logIO("Hello World").run(); // prints and returns undefined

Transformation Operations

Transform IO computations while preserving the IO context.

/**
 * Map function over IO result
 * @param f - Transformation function
 * @returns Function that maps over IO
 */
function map<A, B>(f: (a: A) => B): (fa: IO<A>) => IO<B>;

/**
 * Apply function in IO to value in IO
 * @param fab - IO containing function
 * @returns Function that applies function to IO value
 */
function ap<A, B>(fab: IO<(a: A) => B>): (fa: IO<A>) => IO<B>;

/**
 * Sequence two IOs, keeping first result
 * @param fb - Second IO to execute
 * @returns Function that sequences IOs
 */
function applyFirst<A, B>(fb: IO<B>): (fa: IO<A>) => IO<A>;

/**
 * Sequence two IOs, keeping second result
 * @param fb - Second IO to execute
 * @returns Function that sequences IOs
 */
function applySecond<A, B>(fb: IO<B>): (fa: IO<A>) => IO<B>;

Usage Examples:

import { IO, map, ap } from "fp-ts/lib/IO";

// Transform result
const numberIO = new IO(() => 21);
const doubledIO = map((n: number) => n * 2)(numberIO);
const result = doubledIO.run(); // 42

// Apply function
const addIO = new IO(() => (x: number) => (y: number) => x + y);
const xIO = new IO(() => 10);
const yIO = new IO(() => 20);
const sumIO = ap(ap(addIO)(xIO))(yIO);
const sum = sumIO.run(); // 30

Sequencing Operations

Chain IO computations in sequence.

/**
 * Chain IO computations
 * @param f - Function returning IO
 * @returns Function that chains IOs
 */
function chain<A, B>(f: (a: A) => IO<B>): (fa: IO<A>) => IO<B>;

/**
 * Flatten nested IO
 * @param mma - IO containing IO
 * @returns Flattened IO
 */
function flatten<A>(mma: IO<IO<A>>): IO<A>;

Usage Examples:

import { IO, chain } from "fp-ts/lib/IO";

// Chain operations
const getNumber = new IO(() => 5);
const processNumber = (n: number) => new IO(() => {
  console.log(`Processing ${n}`);
  return n * n;
});

const chainedIO = chain(processNumber)(getNumber);
const result = chainedIO.run(); // prints "Processing 5", returns 25

Type Class Instances

IO implements various type class instances for generic operations.

/**
 * Main IO type class instances
 */
const io: Monad1<URI> & MonadIO1<URI>;

/**
 * Semigroup instance for IO
 * @param S - Semigroup for contained type
 * @returns Semigroup that combines IO results
 */
function getSemigroup<A>(S: Semigroup<A>): Semigroup<IO<A>>;

/**
 * Monoid instance for IO
 * @param M - Monoid for contained type
 * @returns Monoid that combines IO results
 */
function getMonoid<A>(M: Monoid<A>): Monoid<IO<A>>;

Interoperability

Convert between IO and other effect types.

/**
 * Convert IO to Task
 * @param ma - IO to convert
 * @returns Task that executes IO synchronously
 */
function fromIO<A>(ma: IO<A>): Task<A>;

/**
 * Lift IO into other monads
 * @param M - MonadIO instance
 * @returns Function that lifts IO
 */
function liftIO<M extends URIS>(M: MonadIO1<M>): <A>(ma: IO<A>) => Kind<M, A>;

Utility Operations

Helpful utilities for working with IO.

/**
 * Execute multiple IOs in sequence, ignoring results
 * @param ios - Array of IOs to execute
 * @returns IO that executes all in sequence
 */
function sequence_<A>(ios: Array<IO<A>>): IO<void>;

/**
 * Execute IO and return result along with execution time
 * @param ma - IO to time
 * @returns IO returning tuple of [result, milliseconds]
 */
function time<A>(ma: IO<A>): IO<[A, number]>;

Usage Examples:

import { IO, sequence_ } from "fp-ts/lib/IO";

// Execute multiple side effects
const log1 = new IO(() => console.log("First"));
const log2 = new IO(() => console.log("Second"));
const log3 = new IO(() => console.log("Third"));

const allLogs = sequence_([log1, log2, log3]);
allLogs.run(); // prints all three messages in order

Error Handling

While IO never fails, you can handle errors from underlying computations.

/**
 * Try to execute IO, catching exceptions
 * @param f - Function that may throw
 * @returns IO returning Either with result or error
 */
function tryCatch<A>(f: Lazy<A>): IO<Either<Error, A>>;

/**
 * Try to execute IO with custom error handler
 * @param f - Function that may throw
 * @param onError - Function to handle errors
 * @returns IO returning Either with result or custom error
 */
function tryCatchK<E, A>(f: Lazy<A>, onError: (e: unknown) => E): IO<Either<E, A>>;

Usage Examples:

import { IO, tryCatch } from "fp-ts/lib/IO";
import { fold } from "fp-ts/lib/Either";

// Safe JSON parsing
const parseJSON = (str: string) => tryCatch(() => JSON.parse(str));

const safeParseIO = parseJSON('{"name": "Alice"}');
const result = safeParseIO.run();

const message = fold(
  (error: Error) => `Parse failed: ${error.message}`,
  (value: unknown) => `Parsed: ${JSON.stringify(value)}`
)(result);

console.log(message); // "Parsed: {"name":"Alice"}"

Types

// Core IO type
class IO<A> {
  readonly _A!: A;
  readonly _URI!: URI;
  
  constructor(readonly run: Lazy<A>) {}
  
  // Instance methods (deprecated in favor of pipeable operations)
  map<B>(f: (a: A) => B): IO<B>;
  ap<B>(fab: IO<(a: A) => B>): IO<B>;
  chain<B>(f: (a: A) => IO<B>): IO<B>;
  
  // Utility methods
  inspect(): string;
  toString(): string;
}

// URI for type-level programming
const URI = 'IO';
type URI = typeof URI;

// Lazy computation type
type Lazy<A> = () => A;