Do-Notation

Scala-like for-comprehensions

Compose monadic operations elegantly without nested flatMap calls

What is Do-Notation?

Do-notation provides generator-based monadic comprehensions inspired by Scala's for-comprehensions. It makes complex monadic chains readable and maintainable by eliminating nested flatMap calls.

// Chain multiple Option operations
const result = Do(function* () {
  const x = yield* $(Option(5))
  const y = yield* $(Option(10))
  const z = yield* $(Option(2))
  return x + y + z
}) // Some(17)

// Error handling with Either
const validation = Do(function* () {
  const name = yield* $(Right<string, string>("John"))
  const age = yield* $(Right<string, number>(25))
  return { name, age }
})

// Async operations
// eslint-disable-next-line @typescript-eslint/require-await -- Generator function for demo purposes
const _asyncResult = DoAsync(async function* () {
  const data = yield* $(Right("user123"))
  const user = yield* $(Option({ id: data, name: "Alice" }))
  return `User: ${user.name}`
})

Key Features

Scala-Inspired

Similar syntax to Scala's for-comprehensions with generators

Type-Safe

Full TypeScript inference with the $ helper function

Short-Circuiting

None/Left/Failure automatically propagates through the chain

Performance

175x faster than nested flatMaps for List comprehensions

Common Patterns

Option Chaining

const result = Do(function* () {
  const x = yield* $(Option(5))
  const y = yield* $(Option(10))
  return x + y
}) // Option(15)

List Comprehensions (Cartesian Products)

const pairs = Do(function* () {
  const x = yield* $(List([1, 2]))
  const y = yield* $(List([10, 20]))
  return { x, y }
})
// List([{x:1,y:10}, {x:1,y:20}, {x:2,y:10}, {x:2,y:20}])

Error Handling with Either

const validated = Do(function* () {
  const email = yield* $(validateEmail(input))
  const user = yield* $(fetchUser(email))
  const saved = yield* $(saveUser(user))
  return saved
})
// If any step returns Left, chain short-circuits

When to Use Do-Notation

Chaining 3+ monadic operations

Complex workflows with multiple sequential steps

List comprehensions (cartesian products)

Generating combinations, test data, permutations

Prioritizing readability over micro-optimizations

Business logic, validation pipelines, data transformations