Dining philosophers using join calculus

This example shows an implementation of the dining philosophers problem implemented using joinads. The sample has been written by Nick Palladinos (see F# Snippets). The description of the dining philosophers problem from WikiPedia looks like this:

The solution using joinads represents each philosopher and a fork (or a chopstick) using a single channel. The initialization code looks like this:

open System
open FSharp.Extensions.Joinads

// Initialize channel for every philosopher and every chopstick
let n = 5
let chopsticks = [| for i = 1 to n do yield new Channel<unit>() |]
let hungry = [| for i = 1 to n do yield new Channel<unit>() |]
let philosophers = [| "Plato"; "Konfuzius"; "Socrates"; "Voltaire"; "Descartes" |]

let randomDelay (r : Random) = System.Threading.Thread.Sleep(r.Next(1, 10) * 1000)

The situation when a philosopher can start eating is captured by a join pattern that matches on channels representing the philosopher and a fork on the left and on the right:

// Start join patterns that enable philosophers to eat
for i = 0 to n - 1 do
    let left = chopsticks.[i]
    let right = chopsticks.[(i+1) % n]
    let random = new Random()
    join {
        match! hungry.[i], left, right with
        | _, _, _ ->
            printfn "%s is eating" philosophers.[i] 
            randomDelay random
            left.Call(); right.Call()
            printfn "%s is thinking" philosophers.[i] 
    }

Now we can start the code by making all chopsticks (initially) available and by running a loop that makes random philosophers hungry:

// Run
for chopstick in chopsticks do
    chopstick.Call()

let random = new Random()    
for i in 0 .. 10 do
    hungry.[random.Next(0, n)].Call()
    randomDelay random
namespace System
namespace FSharp
namespace FSharp.Extensions
namespace FSharp.Extensions.Joinads
val n : int

Full name: TryJoinads.n
  type: int
  inherits: ValueType
val chopsticks : Channel<unit> []

Full name: TryJoinads.chopsticks
  type: Channel<unit> []
  inherits: Array
val i : int
  type: int
  inherits: ValueType
Multiple items
module Channel

from FSharp.Extensions.Joinads

--------------------
type Channel<'T> =
  class
    interface IChannel<'T>
    new : unit -> Channel<'T>
    member Call : message:'T -> unit
    member Put : message:'T -> unit
  end

Full name: FSharp.Extensions.Joinads.Channel<_>
  type: Channel<'T>
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
  type: unit
val hungry : Channel<unit> []

Full name: TryJoinads.hungry
  type: Channel<unit> []
  inherits: Array
val philosophers : string []

Full name: TryJoinads.philosophers
  type: string []
  inherits: Array
val randomDelay : Random -> unit

Full name: TryJoinads.randomDelay
val r : Random
type Random =
  class
    new : unit -> System.Random
    new : int -> System.Random
    member Next : unit -> int
    member Next : int -> int
    member Next : int * int -> int
    member NextBytes : System.Byte [] -> unit
    member NextDouble : unit -> float
  end

Full name: System.Random
namespace System.Threading
type Thread =
  class
    inherit System.Runtime.ConstrainedExecution.CriticalFinalizerObject
    new : System.Threading.ThreadStart -> System.Threading.Thread
    new : System.Threading.ParameterizedThreadStart -> System.Threading.Thread
    member Abort : unit -> unit
    member CurrentCulture : System.Globalization.CultureInfo with get, set
    member CurrentUICulture : System.Globalization.CultureInfo with get, set
    member GetHashCode : unit -> int
    member IsAlive : bool
    member IsBackground : bool with get, set
    member Join : unit -> unit
    member Join : int -> bool
    member ManagedThreadId : int
    member Name : string with get, set
    member Start : unit -> unit
    member Start : obj -> unit
    member ThreadState : System.Threading.ThreadState
    static member CurrentThread : System.Threading.Thread
    static member GetDomain : unit -> System.AppDomain
    static member MemoryBarrier : unit -> unit
    static member Sleep : int -> unit
    static member Sleep : System.TimeSpan -> unit
    static member SpinWait : int -> unit
  end

Full name: System.Threading.Thread
  type: Threading.Thread
  inherits: Runtime.ConstrainedExecution.CriticalFinalizerObject
Threading.Thread.Sleep(timeout: TimeSpan) : unit
Threading.Thread.Sleep(millisecondsTimeout: int) : unit
Random.Next() : int
Random.Next(maxValue: int) : int
Random.Next(minValue: int, maxValue: int) : int
val left : Channel<unit>
  type: Channel<unit>
val right : Channel<unit>
  type: Channel<unit>
val random : Random
val join : JoinBuilder

Full name: FSharp.Extensions.Joinads.Builders.join
val printfn : Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
member Channel.Call : message:'T -> unit
val chopstick : Channel<unit>
  type: Channel<unit>
val random : Random

Full name: TryJoinads.random
val i : int32
  type: int32
  inherits: ValueType