ExamplesBy LevelBy TopicLearning Paths
193 Expert

Effects as Async

Functional Programming

Tutorial Video

Text description (accessibility)

This video demonstrates the "Effects as Async" functional Rust example. Difficulty level: Expert. Key concepts covered: Functional Programming. Asynchronous I/O is the most widely deployed algebraic effect in mainstream programming. Key difference from OCaml: 1. **State machine vs. continuation**: Rust's `async/await` compiles to a state machine; OCaml's effect

Tutorial

The Problem

Asynchronous I/O is the most widely deployed algebraic effect in mainstream programming. Rust's async/await transforms async functions into state machines that yield control at each await point — the runtime (Tokio, async-std) is the "handler" that resumes computations when I/O completes. This example explores the conceptual connection between algebraic effects and async, showing how Future and Poll are the concrete Rust implementation of the "suspend and resume" effect model.

🎯 Learning Outcomes

  • • Understand async/await as syntactic sugar over the Future trait and algebraic effects
  • • Learn how Poll::Pending and Poll::Ready correspond to effect suspension and resumption
  • • See how the Tokio runtime acts as an effect handler for I/O effects
  • • Connect the free monad interpretation (program as data) to the async state machine model
  • Code Example

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

    Key Differences

  • State machine vs. continuation: Rust's async/await compiles to a state machine; OCaml's effect-based async uses captured continuations — different implementations of the same semantics.
  • Zero-cost: Rust's state machine approach has zero heap allocation per await in typical use; OCaml's continuation capture allocates on the heap.
  • Expressiveness: OCaml's effect-based async supports multi-shot continuations (forking); Rust's Future is single-shot.
  • Ecosystem: Rust's async ecosystem (Tokio, Hyper, SQLx) is mature and widely used; OCaml's eio is newer but gaining adoption.
  • OCaml Approach

    OCaml's eio library (built on OCaml 5 effects) implements async I/O via effects:

    effect Await : 'a Promise.t -> 'a
    let with_scheduler program =
      match_with program () { effc = fun (type a) e ->
        match e with
        | Await p -> Some (fun k ->
            Promise.on_resolve p (fun v -> continue k v))
        | _ -> None }
    

    The Await effect is intercepted by the scheduler, which registers the continuation and resumes it when the promise resolves.

    Full Source

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

    Deep Comparison

    OCaml vs Rust: Effect Async

    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 minimal future executor that polls a set of futures in a round-robin loop until all complete.
  • Write a join_all<F: Future>(futures: Vec<F>) -> Vec<F::Output> that concurrently awaits all futures.
  • Implement a timeout combinator: with_timeout(duration, future) that returns Err(Timeout) if the future takes too long.
  • Open Source Repos