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 the F# programming language. Based on pure functional programming principles, it serves as an embedded domain-specific language (DSL) empowering developers to craft type-safe, concurrent and maintainable programs with ease. Initially conceived and developed as part of a master’s thesis, which you can explore further here.
Harnessing concepts from functional programming, FIO simplifies the creation of scalable and efficient concurrent applications. It introduces the IO monad to manage expressions with side effects and employs “green threads” (also known as fibers) for scalable and efficient concurrency. FIO aims to provide an environment similar to that of ZIO for Scala, drawing inspiration from both ZIO and Cats Effect.
Below is a simple example showcasing the usage of FIO. After importing the library, a program named askForName prompts the user for their name. This program is then interpreted by FIO’s advanced runtime and the fiber is asynchronously awaited for the result.
// file: "PromptUser.fs"
open FSharp.FIO
let askForName = fio {
do! printfn "%s" "Hello! What is your name?"
let! name = Console.ReadLine()
do! printfn $"Hello, %s{name}, welcome to FIO!"
}
let fiber = Advanced.Runtime().Run askForName
let result = fiber.Await()
printfn $"%A{result}"
FIO facilitates message passing through channels, as demonstrated in the example below. Two programs, pinger and ponger, communicate by exchanging messages via channels chan1 and chan2.
// file: "MessagePassing.fs"
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}"
FIO simplifies the creation of highly concurrent programs capable of spawning thousands of fibers simultaneously. Below is a straightforward example of a many-to-one message passing program, where 100.000 fibers are spawned, each sending a message to a single receiving fiber.
// file: "Concurrency.fs"
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}"
For more detailed information about the library, please refer to the README file in the referred GitHub repository or the referred thesis.