Skip to content

feat(lang): add generators with yield #12

Description

@eddmann

Summary

Add generator functions to santa-lang for creating lazy, on-demand sequences using yield.

Description

Generators allow defining iterators in a natural, imperative style. Instead of computing all values upfront, generators produce values one at a time, enabling memory-efficient processing of large or infinite sequences.

Proposed Syntax

Basic Generator

let countdown = |n| gen {
  while n > 0 {
    yield n;
    n = n - 1;
  }
};

countdown(5) |> take(3) |> collect;  // [5, 4, 3]

Infinite Sequences

let naturals = gen {
  let n = 0;
  loop {
    yield n;
    n = n + 1;
  }
};

naturals |> take(5) |> collect;  // [0, 1, 2, 3, 4]

Fibonacci Generator

let fibonacci = gen {
  let [a, b] = [0, 1];
  loop {
    yield a;
    [a, b] = [b, a + b];
  }
};

fibonacci |> take(10) |> collect;  // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

Generator with Parameters

let range = |start, end, step| gen {
  let i = start;
  while i < end {
    yield i;
    i = i + step;
  }
};

range(0, 10, 2) |> collect;  // [0, 2, 4, 6, 8]

Yield From (Delegation)

let flatten = |nested| gen {
  for list in nested {
    yield* list;  // yield all items from sub-iterator
  }
};

flatten([[1, 2], [3, 4]]) |> collect;  // [1, 2, 3, 4]

Integration with Existing Features

Pipeline Compatibility

let evens = gen {
  let n = 0;
  loop {
    yield n;
    n = n + 2;
  }
};

evens
  |> take(100)
  |> filter(|n| n % 4 == 0)
  |> map(|n| n * n)
  |> take(5)
  |> collect;

Pattern Matching

match some_generator() {
  gen => "it's a generator",
  _ => "something else"
}

Implementation Considerations

  • Coroutine-based - Generators as stackless coroutines
  • State machine - Transform generator body into state machine
  • Lazy evaluation - Values computed only when requested
  • Memory - Generator state must be preserved between yields
  • Interaction with existing sequences - Lazy sequences already exist, how do generators relate?

Alternative Syntax Options

// Option A: gen block
let nums = gen { yield 1; yield 2; };

// Option B: Generator function marker
let nums = generator |n| { yield n; };

// Option C: Arrow with asterisk (JS-style)
let nums = |n| *=> { yield n; };

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions