FIO

FIO

A type-safe, highly concurrent and asynchronous library for F# based on pure functional programming

FIO is a type-safe, highly concurrent and asynchronous library for F# that is based on principles from pure functional programming. It is an implementation of an embedded domain-specific language for making type-safe and concurrent programs that are easy to use and maintain. FIO was designed and implemented as part of a master’s thesis which can be read here.

FIO uses concepts from functional programming to make it easy for developers to create scalable and efficient concurrent programs. It provides a construct known as the IO monad for handling expressions with side effects. It uses the concept of “green threads” also known as “fibers” to provide scalable and efficient concurrency. FIO is an attempt at creating a similar environment to that of ZIO for Scala and is both inspired by ZIO and Cats Effect.

The following program is a simple example of using FIO. The library is simply imported and a program that asks the user for their name called askForName is shown. It is interpreted by FIO’s advanced runtime and the fiber is awaited asynchronously for the result.

open FSharp.FIO

let askForName =
  fio (fun () -> printfn "%s" "Hello! What is your name?")
  >> fun _ ->
  fio (fun () -> Console.ReadLine())
  >> fun name ->
  fio (fun () -> printfn $"Hello, %s{name}, welcome to FIO!")
  
let fiber = Advanced.Runtime().Run askForName
let result = fiber.Await()
printfn $"%A{result}"

FIO supports message passing through channels as seen in the example below. Two programs pinger and ponger exchange messages through channels chan1 and chan2.

open FSharp.FIO

let pinger chan1 chan2 =
  let ping = "ping"
  send ping chan1 >> fun _ ->
  printfn $"pinger sent: %s{ping}"
  receive chan2 >> fun pong ->
  printfn $"pinger received: %s{pong}"
  stop

let ponger chan1 chan2 =
  receive chan1 >> fun ping ->
  printfn $"ponger received: %s{ping}"
  let pong = "pong"
  send pong chan2 >> fun _ ->
  printfn $"ponger sent: %s{pong}"
  stop

let chan1 = Channel<string>()
let chan2 = Channel<string>()
let pingpong = pinger chan1 chan2 ||| ponger chan1 chan2

let fiber = Advanced.Runtime().Run pingpong
let result = fiber.Await()
printfn $"%A{result}"

Using FIO makes it straightforward to create highly concurrent programs that spawn thousands of fibers at once. Below is a simple many-to-one message passing program that spawns 100.000 fibers that each send a message to a single receiving fiber.

open FSharp.FIO

let sender chan id =
  let msg = 42
  send msg chan >> fun _ ->
  printfn $"Sender[%i{id}] sent: %i{msg}"
  stop

let rec receiver chan count =
  if count = 0 then
    stop
  else
    receive chan >> fun msg ->
    printfn $"Receiver received: %i{msg}"
    receiver chan (count - 1)

let rec create chan count acc =
  if count = 0 then
    acc
  else
    let newAcc = sender chan count |||* acc
    create chan (count - 1) newAcc

let fiberCount = 100000
let chan = Channel<int>()
let acc = sender chan fiberCount |||* receiver chan fiberCount
let program = create chan (fiberCount - 1) acc

let fiber = Advanced.Runtime().Run program
let result = fiber.Await()
printfn $"%A{result}"

More in-depth information about the project can be found in the README of its source repository.