0Pricing
Swift Academy · Lesson

Building Custom Lazy Sequences

Create your own lazily-evaluated sequences.

Building Custom Lazy Sequences is a free Swift Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Swift Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Why Custom Lazy?

Beyond map and filter, you can build your own lazily-evaluated sequences for things like infinite generators or expensive computed streams that should run on demand.

The LazySequence Type

Calling .lazy wraps a collection in a LazySequenceProtocol conformer. Operations you add return more lazy wrappers:

let view = [1, 2, 3].lazy
let mapped = view.map { $0 * 2 }
print(Array(mapped))  // [2, 4, 6]  -- LazyMapSequence

A Pull-Based Sequence

Custom sequences are pull-based: each call to the iterator computes the next value only when asked. Here is a Fibonacci generator:

struct Fibonacci: Sequence, IteratorProtocol {
    var a = 0, b = 1
    mutating func next() -> Int? {
        let r = a
        (a, b) = (b, a + b)
        return r
    }
}
print(Array(Fibonacci().prefix(6)))  // [0, 1, 1, 2, 3, 5]

Infinite, Consumed Lazily

Because values are pulled on demand, an infinite sequence is safe as long as you take a finite slice:

struct Naturals: Sequence, IteratorProtocol {
    var n = 1
    mutating func next() -> Int? { defer { n += 1 }; return n }
}
print(Array(Naturals().prefix(4)))  // [1, 2, 3, 4]

Conforming to LazySequenceProtocol

Adopting LazySequenceProtocol makes your own type chain lazily with map/filter too:

struct Counter: Sequence, IteratorProtocol, LazySequenceProtocol {
    var n = 0; let limit: Int
    mutating func next() -> Int? {
        guard n < limit else { return nil }
        defer { n += 1 }
        return n
    }
}
print(Array(Counter(n: 0, limit: 3).map { $0 * 10 }))  // [0, 10, 20]

sequence(first:next:)

The standard library gives you a builder for custom lazy sequences without a new type:

let powers = sequence(first: 1) { $0 <= 16 ? $0 * 2 : nil }
print(Array(powers))  // [1, 2, 4, 8, 16, 32]

sequence(state:next:)

Carry richer state between steps:

let fibs = sequence(state: (0, 1)) { (s: inout (Int, Int)) -> Int? in
    let r = s.0
    s = (s.1, s.0 + s.1)
    return r
}
print(Array(fibs.prefix(6)))  // [0, 1, 1, 2, 3, 5]

AnySequence Wrapper

Hide the concrete type behind AnySequence when exposing an API:

func evens(upTo n: Int) -> AnySequence<Int> {
    AnySequence((0...n).lazy.filter { $0 % 2 == 0 })
}
print(Array(evens(upTo: 8)))  // [0, 2, 4, 6, 8]

Lazy Computed Stream

Defer expensive work until each element is actually consumed:

let stream = (1...5).lazy.map { (n: Int) -> Int in
    print("computing \(n)")
    return n * n
}
print(stream.first!)  // computing 1, then 1

Stopping a Generator

Return nil from next() to end the sequence cleanly:

let countdown = sequence(state: 3) { (s: inout Int) -> Int? in
    guard s > 0 else { return nil }
    defer { s -= 1 }
    return s
}
print(Array(countdown))  // [3, 2, 1]

Putting It Together

Combine a custom generator with lazy operators for an on-demand pipeline:

let primesIsh = sequence(first: 2) { $0 < 20 ? $0 + 1 : nil }
    .lazy
    .filter { n in (2..<n).allSatisfy { n % $0 != 0 } }
print(Array(primesIsh))  // [2, 3, 5, 7, 11, 13, 17, 19]

Quick Check

What signals the end of a custom IteratorProtocol sequence?

Recap

You learned custom lazy sequences:

  • .lazy produces LazySequenceProtocol wrappers
  • Implement Sequence + IteratorProtocol; next() returns nil to stop
  • Use sequence(first:next:) / sequence(state:next:) as quick builders
  • Wrap in AnySequence to hide concrete types

Course complete! Next: closures deep dive.

Frequently asked questions

Is the “Building Custom Lazy Sequences” lesson free?

Yes — the full text of “Building Custom Lazy Sequences” is free to read here on the web, and the Swift Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Swift Academy course, upgrade to CoddyKit PRO.

What will I learn in “Building Custom Lazy Sequences”?

Create your own lazily-evaluated sequences. You practise Swift Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Swift Academy?

No prior experience is required. Swift Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Building Custom Lazy Sequences” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Swift Academy lesson?

Yes. Every Swift Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. The lazy Property
  2. Lazy map and filter
  3. Lazy vs Eager Trade-offs
  4. Building Custom Lazy Sequences
← Back to Swift Academy