ExamplesBy LevelBy TopicLearning Paths
196 Expert

Delimited Continuations

Functional Programming

Tutorial Video

Text description (accessibility)

This video demonstrates the "Delimited Continuations" functional Rust example. Difficulty level: Expert. Key concepts covered: Functional Programming. Full continuations (`callcc`) capture the entire remaining computation. Key difference from OCaml: 1. **Native support**: OCaml 5's effect system is built on delimited continuations; Rust requires simulation or `unsafe` code.

Tutorial

The Problem

Full continuations (callcc) capture the entire remaining computation. Delimited continuations capture only the computation up to a "delimiter" — a prompt that marks the boundary. This makes them composable and less dangerous than full continuations. Delimited continuations are the foundation of effect handlers (OCaml 5), generators, and async/await. Understanding them reveals how all these features share a common computational model.

🎯 Learning Outcomes

  • • Understand the difference between full and delimited continuations
  • • Learn reset (sets the delimiter) and shift (captures the delimited continuation)
  • • See how delimited continuations generalize generators, exceptions, and async
  • • Understand why OCaml 5's effect handlers are implemented via delimited continuations
  • Code Example

    #![allow(clippy::all)]
    // Stub — awaiting conversion from OCaml source.

    Key Differences

  • Native support: OCaml 5's effect system is built on delimited continuations; Rust requires simulation or unsafe code.
  • Multi-shot: OCaml's continue k can be called multiple times (non-determinism, backtracking); Rust's FnOnce and Box<dyn FnOnce> are single-shot only.
  • Stack frames: OCaml captures actual stack frames as continuations — zero-copy; Rust's simulation copies data into closures.
  • Composability: Delimited continuations in OCaml compose via nested match_with; Rust's simulation composes poorly beyond simple cases.
  • OCaml Approach

    OCaml 5 implements delimited continuations natively:

    let () =
      match_with (fun () ->
        let k = perform (Shift (fun k -> k)) in  (* capture delimited cont *)
        Printf.printf "resumed\n";
        perform (Resume k)  (* resume it *)
      ) () { ... }
    

    The delimcc library (for older OCaml) provides new_prompt, push_prompt, and shift0 / control0 as the full delimited continuation API.

    Full Source

    #![allow(clippy::all)]
    // Stub — awaiting conversion from OCaml source.

    Deep Comparison

    OCaml vs Rust: Delimited Cont

    Overview

    See the example.rs and example.ml files for detailed implementations.

    Key Differences

    AspectOCamlRust
    Type systemHindley-MilnerOwnership + traits
    MemoryGCZero-cost abstractions
    MutabilityExplicit refmut keyword
    Error handlingOption/ResultResult<T, E>

    See README.md for detailed comparison.

    Exercises

  • Implement a generator using the delimited continuation simulation: yield_value shifts, next_value resets.
  • Implement simple backtracking: amb([1, 2, 3]) tries all options using multi-shot continuation semantics.
  • Write a reset/shift combination that implements Result propagation — shift throws an error, reset catches it.
  • Open Source Repos