# \`fp\_mojo\` 1.0.2 — Now with Structured Async IO and Mojo 1.2 Support! 🚀

**URL:** <https://forum.modular.com/t/fp-mojo-1-0-2-now-with-structured-async-io-and-mojo-1-2-support/3621>\
**Category:** Community Showcase\
**Created:** [November 2, 2026, 11:51am UTC](https://forum.modular.com/t/fp-mojo-1-0-2-now-with-structured-async-io-and-mojo-1-2-support/3621 "2026-11-02T11:51:14Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![anatolvitold](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.modular.com/anatolvitold/32/1326_2.png) [@anatolvitold](https://forum.modular.com/u/anatolvitold)\
**Post date:** [November 2, 2026, 11:51am UTC](https://forum.modular.com/t/fp-mojo-1-0-2-now-with-structured-async-io-and-mojo-1-2-support/3621/1 "2026-11-02T11:51:14Z")

</div>

I took @maxchisto’s and @Kausch’s advice to heart and incorporated a lot of design decisions from [Cats](https://github.com/typelevel/cats) and [Cats Effect](https://github.com/typelevel/cats-effect) into `fp_mojo`, especially around syntax and our new **structured asynchronous IO runtime**.  
With the release of **`fp_mojo` 1.0.2** , the library is fully upgraded and qualified for **Mojo 1.2.0** on both **Linux x86-64** and **macOS arm64**.

* * *

In addition to composable functional abstractions—fluent pipelines, zero-allocation lazy streaming, inductive algebraic data types, and compile-time exhaustive pattern matching—the library now includes a structured asynchronous concurrency engine. Programs coordinate non-blocking I/O through lightweight cancelable fibers, a multi-threaded work-stealing scheduler, and deterministic virtual-time simulation, preserving Mojo’s explicit memory ownership and exact compiler error types.

* * *

## Architectural Highlights

### 1. Structured Asynchronous Concurrency (`fp.effects.async_runtime`)

Rather than relying on unmanaged OS threads or unchecked callback graphs, `IO[T, E]` describes a program without running it: building one runs nothing, and each value runs once.

- **Bounded Native Stack** : Evaluation occurs through an iterative, trampolined run loop on a dedicated frame stack list whose growth amortizes to ~126 bytes per frame of a runtime-built chain. Deep monadic chains, nested `IO.defer` expressions, and `tail_rec_m` loops execute in constant native stack depth, preventing call-stack overflow under a 1 MiB stack limit.
- **Lightweight Cancelable Fibers** : Fibers are managed concurrent tasks; a start and join takes ~6.8 µs. Started via `.start()`, concurrent branches coordinate through `.both()` (parallel combination), `.race()` / `.race_pair()` (first-result selection), and `Supervisor[E].scoped` (lexical supervisor scopes). Fibers yield cooperatively and, by default, run in parallel on worker threads.
- **Automatic Cancellation & Draining Invariants** : Child fibers remain structurally owned by their enclosing scope. When a parent task completes, errors, or cancels, uncompleted child fibers are automatically notified via atomic cancellation tokens and cooperatively drained through their masked cleanup finalizers before the parent finishes.

### 2. Multi-Threaded Work-Stealing Topologies

- **Work-Stealing Pool (`Profile.work_stealing`)**: The default profile on multi-processor architectures manages worker threads via local ring deques (`_LocalQueue`) with LIFO optimization, a striped external queue (`_ExternalQueue`), per-worker timer heaps, and descriptor readiness polling.
- **Cooperative Single-Thread Profile (`Profile.current_thread`)**: Drives asynchronous tasks deterministically on the calling host thread without thread switching or lock contention.
- **Isolated Blocking Offload (`BlockingPool`)**: Synchronous system calls and CPU-intensive operations are offloaded via `IO.blocking(...)` or cancelable `IO.interruptible(...)` to dedicated, cached thread pools, preventing worker thread starvation.

### 3. Payload Thread Safety & Formal Memory Ordering Audit

Mojo does not yet implement native compiler-verified `Send` and `Sync` traits. `fp_mojo` provides compile-time safety boundaries and audited atomic orderings:

- **Static Field-Tree Inspection** : `_Erased. __init__ [T]` inspects the recursive field layout of any erased async payload, rejecting structs that reach raw `Pointer` or unsynchronized reference fields unless explicitly marked as conforming to `ThreadTransferable`.
- **Memory Ordering Invariants** : All synchronization primitives (`_OneShot` slot claim/publish, `_ClosableStack`, task scheduling headers, and wake registry notifications) document their atomic acquire-release fences, lost-wake handshakes, and sequential consistency barriers.

### 4. Deterministic Virtual-Time Simulation (`TestControl`)

Asynchronous scheduling, timeout races, and cancellation protocols can be verified deterministically without wall-clock sleeps or non-deterministic test latency:

```mojo
from fp.effects import EffectFailure, fold_outcome
from fp.effects.async_runtime import IO, Duration, TestControl

def success(value: Int) -> Int: return value
def failure(var errors: EffectFailure[Int]) -> Int: return -1
def canceled() -> Int: return 0

def main() raises:
    # A 60-second asynchronous sleep with a 5-second timeout fallback:
    var slow = IO[NoneType, Int].sleep(Duration.seconds(60)).map(lambda (unit: NoneType) -> Int: 42)
    var program = slow^.timeout_to(Duration.seconds(5), IO[Int, Int].pure(7))

    # TestControl advances virtual time instantly without wall-clock execution:
    var control = TestControl(program^)
    control.tick() # Advances virtual clock to the earliest deadline (5s)
    control.tick_all() # Drains virtual-time timers and completes execution
    print("result:", fold_outcome(control^.results(), success, failure, canceled)) # result: 7

```

### 5. Resumable Coordination Primitives

State transitions reuse canonical synchronous logic behind non-blocking polling guards:

- `Deferred[T]`: Single-assignment cell for asynchronous result publishing; every waiting reader receives a copy.
- `Ref[T]`: Synchronized cell whose updates are atomic with respect to other fibers.
- `Queue[T]`: Bounded FIFO queue supporting backpressure and move-only elements.
- `Semaphore`: Non-negative permit counter that suspends fibers until a permit is available (no waiter-fairness guarantee).

### 6. Independent Error Accumulation & MTL Capabilities

- **Error Accumulation (`par_map_n`, `par_traverse`)**: Validates independent computations via `ValidationFamily`, preserving _all_ aggregated domain errors rather than short-circuiting on the first failure.
- **`NonEmptyList` and `Ior`** : Typed data structures providing guaranteed non-empty error collections and inclusive-or outcomes (valid values accompanied by accumulated warnings).
- **Cats MTL Capability Traits** : Abstract effect capabilities (`Ask`, `Local`, `Stateful`, `Tell`, `Listen`, `Censor`) implemented via compile-time capability dictionaries over monad transformers (`ReaderT`, `StateT`, `WriterT`, `ResultT`).

* * *

## Code Examples

### Independent Error Validation with `par_map_n`

```mojo
from fp.data import Result, Ok, Err
from fp.functions import pipeline

comptime Checked = Result[Int, List[String]]

def positive(value: Int) -> Checked:
    if value <= 0:
        return Err(List[String]([String(value) + " must be positive"]))
    return Ok(value)

def total(a: Int, b: Int, c: Int) -> Int:
    return a + b + c

def main():
    # Both negative inputs fail independently; par_map_n preserves both failures:
    var invalid = pipeline(positive(-2)).par_map_n((positive(3), positive(-4)), total).get()
    try:
        _ = invalid^.raise_on_err()
    except errors:
        for error in errors:
            print("validation error:", error)
    # validation error: -2 must be positive
    # validation error: -4 must be positive

```

### Monadic Async Sequencing and Outcome Settlement

```mojo
from fp.effects import EffectFailure, fold_outcome
from fp.effects.async_runtime import IO, run
from fp.functions import pipeline

def next_value(value: Int) -> IO[Int, Int]:
    return IO[Int, Int].pure(value + 2)

def initial() -> Int:
    return 40

def success(value: Int) -> Int: return value
def failure(var errors: EffectFailure[Int]) -> Int: return -100
def canceled() -> Int: return -200

def main():
    var program = pipeline(IO[Int, Int].delay(initial)).flat_map(next_value).get()
    print("result:", fold_outcome(run(program^), success, failure, canceled)) # 42

```

* * *

## Package Architecture

| Package | Responsibility | Primary APIs |
| --- | --- | --- |
| `fp.effects.async_runtime` | Structured asynchronous runtime and concurrency primitives | `IO` (`.both`, `.race`, `.sleep`, `.timeout_to`, `.background`), `Fiber`, `Supervisor`, `Resource`, `Driver`, `TestControl`, `Runtime`, `Deferred`, `Queue`, `Semaphore` |
| `fp.effects.async_runtime.protocols` | Extension protocols for custom async leaves and scoped borrowing | `Machine`, `ScopedMachine`, `CleanupMachine`, `Context`, `Step`, `Wait`, `Signal` |
| `fp.effects` | Synchronous IO, resource scopes, and monad transformers | `Reader`, `State`, `Writer`, `ReaderT`, `StateT`, `WriterT`, `OptionalT`, `ResultT`, `IO`, `Resource`, `Outcome`, `delay`, `run_io`, `guarantee` |
| `fp.algebra` | Category-theoretic typeclasses and instances | `Functor`, `Filterable`, `Applicative`, `Monad`, `Traversable`, `Semigroup`, `Monoid`, `par_traverse`, `tail_rec_m` |
| `fp.data` | Typed algebraic results and error channels | `Result`, `Ok`, `Err`, `ControlFlow`, `Ior`, `NonEmptyList`, `raise_on_err`, `collect_results` |
| `fp.adt` | In-place and recursive algebraic data types | `Data`, `Cases`, `Node` (recursive values with shared subtrees), `Choice` (stack-allocated variant) |
| `fp.matching` | Exhaustive pattern matching and term rewriting | `fp.match`, `fp.rewrite`, `fp.when`, `Next`, `Guarded` |
| `fp.iteration` | Zero-allocation lazy adapters and terminal folds | `map`, `filter`, `filter_map`, `flat_map`, `flatten`, `scan_left`, `fold_left`, `fold_until`, `collect_list` |
| `fp.functions` | Eager pipelines, function composition, and partial application | `pipeline` (`.par_map_n`), `pipe`, `flow`, `compose`, `flip`, `partial`, `identity` |
| `fp.callables` | Fixed-arity callable protocols and receiver dispatch | `Unary`, `Binary`, `Thunk`, `BorrowCallable`, `as_unary`, `as_binary`, `call_once`, `call_repeated` |

* * *

## Installation & Getting Started

Install via [Pixi](https://pixi.sh) with the Modular community channel (Coming soon [https://github.com/modular/modular-community/pull/443](https://github.com/modular/modular-community/pull/443) ):

```sh
pixi add fp_mojo "mojo==1.2.0"

```

Or clone the repository directly:

```sh
git clone https://github.com/Spellbound-Mojo/fp_mojo.git
cd fp_mojo
pixi install --locked
pixi run mojo run -I src docs/examples/quickstart.mojo
pixi run mojo run -I src docs/examples/async_sequencing.mojo

```

### Documentation & Learning

The complete documentation suite, including our 14-part tutorial series, guides, and API reference, is published at:

- 📖 **Documentation & 14-Chapter Tutorial** : [https://spellbound-mojo.github.io/fp\_mojo/](https://spellbound-mojo.github.io/fp_mojo/)
- 💻 **GitHub Repository** : [https://github.com/Spellbound-Mojo/fp\_mojo](https://github.com/Spellbound-Mojo/fp_mojo)
- 🚀 **Tutorials 10–14** : Dedicated guides for Error Accumulation, MTL Capabilities, Async IO, Fibers & Concurrency, and Running/Testing with `TestControl`.
