playground

tcmts.examples.effect.playground · #oygviqe4 · ts file

// tcm: namespace demo
import { catchTag, fail, gen, runPromise, runSync, sleep, succeed } from "#codebase/effect/Effect";
import type { Effect } from "#codebase/effect/Effect";
import { TaggedError } from "#codebase/effect/Data";
import assert from "node:assert/strict";

/** A sum that went over {@link limit}. */
export class Overflow extends TaggedError("Overflow")<{ readonly at: number }> {}

/** The largest sum {@link add} gives. */
export const limit = 100;

/**
 * Two numbers added, as an Effect that fails with {@link Overflow} past {@link limit}.
 *
 * ```ts
 * runSync(add(20, 22))
 * ```
 */
export const add = (a: number, b: number): Effect<number, Overflow> =>
  gen(function* () {
    const sum = (yield* succeed(a)) + (yield* succeed(b));
    if (sum > limit) return yield* fail(new Overflow({ at: sum }));
    return sum;
  });

/** {@link add}, with an {@link Overflow} turned into its sum, negated. */
export const addOrNegate = (a: number, b: number): Effect<number> =>
  catchTag(add(a, b), "Overflow", (e) => succeed(-e.at));

/** Runs the playground's programs, one of them asynchronously. */
export const main = async () => {
  console.log("sync", runSync(add(20, 22)));
  console.log("caught", runSync(addOrNegate(60, 70)));
  console.log(
    "async",
    await runPromise(
      gen(function* () {
        yield* sleep("10 millis");
        return "slept";
      }),
    ),
  );
};

export const testAdd = () => assert.equal(runSync(add(20, 22)), 42);
export const testOverflowIsCaught = () => assert.equal(runSync(addOrNegate(60, 70)), -130);

used by