
FIO is a type-safe, purely functional effect system for F#: an IO monad plus lightweight fibers (green threads) for building concurrent and asynchronous applications. Effects are described as pure, lazy values and executed by a pluggable runtime, so your program stays a composable, referentially transparent description until you hand it off to be run. The API takes its cues from ZIO and Cats Effect.
If you're wondering why you'd want to program this way in the first place, I wrote about that in Understanding Functional Effect Systems.
#Key Features
- 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 between them - Structured concurrency — fail-fast parallel combinators (
ZipPar,Race,forEachPar) that interrupt losers automatically - Finalizer guarantees —
Ensuringfinalizers run on success, error, and interruption - Composable — the
fio { }computation expression plus a rich set of operators (>>=,<&>,<|>)
#Quick Start
dotnet add package FSharp.FIOopen 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()#Concurrency
Fork effects onto fibers, run them in parallel, and compose the results — on the first failure, the losing fibers are interrupted automatically:
open FIO.DSL
// Run two effects in parallel with <&> and collect both results as a tuple.
let taskA = FIO.succeed "Task A completed! ✅"
let taskB = FIO.succeed (200, "Task B OK ✅")
let both = taskA <&> taskB
// Or fork/join explicitly.
let forked = FIO.succeed("Hello, concurrency! 🚀").Fork() >>= fun fiber -> fiber.Join()#Runtimes
Effects are interpreted by a runtime, and you can pick the one that fits:
| Runtime | Notes |
|---|---|
DirectRuntime |
Single-threaded, synchronous. Handy for tests and simple programs. |
PollingRuntime |
Multi-threaded, linear-time handling of blocked fibers (polling). |
SignalingRuntime |
Multi-threaded, event-driven handling of blocked fibers. |
WorkStealingRuntime |
Multi-threaded, work-stealing scheduler. The default. |
#Ecosystem
Beyond the core FSharp.FIO package, extension libraries bring effects to the network stack: FSharp.FIO.Http (Kestrel-based HTTP server), FSharp.FIO.Sockets (TCP sockets), and FSharp.FIO.WebSockets.
I initially developed FIO at DTU and have kept building on it since. Explore the full API, examples, and documentation in the repository.