README.md

September 17, 2026 ยท View on GitHub

FIO

๐Ÿชป A Type-Safe, Purely Functional Effect System for F#

NuGet Run Tests License: MIT .NET 10


FIO is an IO monad plus lightweight fibers (green threads) for building concurrent and asynchronous F# applications. Effects are described as pure, lazy values and run by a pluggable runtime โ€” so your program is a composable description that stays referentially transparent until you hand it to a runtime. The API takes its cues from ZIO.

  • Typed effects โ€” FIO<'A, 'E> tracks both the success value and the error in the type
  • Fibers & channels โ€” green threads via .Fork() / .Join() and typed message passing
  • Structured concurrency โ€” fail-fast parallel combinators that interrupt losers automatically
  • Finalizer guarantees โ€” Ensuring finalizers run on success, error, and interruption
  • Composable โ€” the fio { } computation expression plus a rich set of operators

Install

dotnet add package FSharp.FIO

Quick Start

open FIO.DSL
open FIO.App
open FIO.Console

type App() =
    inherit FIOApp<unit, exn>()

    override _.effect = fio {
        do! Console.printLine "What is your name?" id
        let! name = Console.readLine id
        do! Console.printLine $"Hello, {name}!" id
    }

[<EntryPoint>]
let main _ = App().Run()

FIOApp runs effect, then onOutcome with the settled result, then onShutdown, and exits with mapExitCode. Ctrl+C and SIGTERM interrupt the effect; its finalizers run before the hooks, so cleanup that needs effect state belongs in Ensuring/acquireReleaseWith, and onShutdown is for process-level goodbyes. A finalizer that never completes holds shutdown; a second Ctrl+C or SIGTERM terminates the process. A defect or an invalid argument in the effect is a fatal error (exit code 2), not an interruption (130).

Concurrency

Fork effects onto fibers, run them in parallel, and compose the results โ€” losers are interrupted automatically on the first failure.

open FIO.DSL

// Run two effects in parallel with <&> and collect both results as a tuple.
let taskA: FIO<string, exn> = FIO.succeed "Task A completed! โœ…"
let taskB: FIO<int * string, exn> = FIO.succeed (200, "Task B OK โœ…")
let both = taskA <&> taskB

// Or fork/join explicitly.
let forked: FIO<string, exn> =
    FIO.succeed("Hello, concurrency! ๐Ÿš€").Fork() >>= fun fiber -> fiber.Join()

More in examples/ โ€” the DSL, App, HTTP, Sockets, and WebSockets tours.

Features

  • Effects โ€” lazy, composable FIO<'A, 'E> with typed errors
  • Fibers โ€” green threads for scalable concurrency
  • Channels โ€” typed message passing between fibers
  • Structured concurrency โ€” fail-fast ZipPar, Race, and forEachPar that interrupt losers automatically
  • Composition โ€” fio { } CE, operators (>>=, <&>, <|>), combinators
  • Refs โ€” Ref<'A>, an atomic reference cell shared between fibers (with FIO.DSL open it shadows FSharp.Core's Ref<'T> annotation; 'T ref is unaffected)
  • Modules โ€” Console

Runtimes

Effects are interpreted by a runtime. Pick one explicitly, or use DefaultRuntime.

RuntimeNotes
DirectRuntimeMulti-threaded via the .NET thread pool โ€” one task per fiber, no scheduler of its own. Handy for tests and as a baseline.
PollingRuntimeMulti-threaded, linear-time handling of blocked fibers (polling).
SignalingRuntimeMulti-threaded, event-driven handling of blocked fibers.
WorkStealingRuntimeMulti-threaded, work-stealing scheduler. The default.

DefaultRuntime = WorkStealingRuntime โ€” FIOApp uses it unless you override _.runtime.

Benchmarks

Twelve concurrency workloads (Pingpong, Threadring, Chameneos, Philosophers, โ€ฆ) run against every runtime, reporting execution time and allocations. Pingpong is tracked per commit on the live benchmark dashboard; the full suite, its parameters, and the A/B comparison protocol are documented in benchmarks/FIO.Benchmarks/README.md.

Packages

PackageDescription
FSharp.FIOCore โ€” effects, fibers, channels, runtimes
FSharp.FIO.HttpHTTP server (Kestrel)
FSharp.FIO.SocketsTCP sockets
FSharp.FIO.WebSocketsWebSockets

Each extension library has its own README with API details: Http ยท Sockets ยท WebSockets.

Contributing

Issues and pull requests welcome. See CONTRIBUTING.md, the Code of Conduct, and the Security Policy.

License

MIT