let tid () = System.Threading.Thread.CurrentThread.ManagedThreadId let sleep (ms : int) = System.Threading.Thread.Sleep(ms) type IAgent<'msg> = abstract member Inbox : MailboxProcessor<'msg * IAgent<'msg>> abstract member Send : 'msg * IAgent<'msg> -> unit type Msg = | Stop | Ping of int | Pong of int let send msg receiver sender = sleep (1000) (sender :> IAgent).Send(msg, receiver) type pingActor() as self = let receiver (inbox : MailboxProcessor>) = let rec loop () = async { let! (msg, actor) = inbox.Receive() match msg with | Pong(n) -> printfn "[%d] Ping received pong : %d" (tid()) n if n > 1 then self |> send (Ping (n - 1)) actor return! loop () else printfn "[%d] Ping finished" (tid()) self |> send Stop actor return () | _ -> return! loop () } loop () let inbox = MailboxProcessor.Start(receiver) interface IAgent with member this.Inbox = inbox member this.Send(msg, actor) = actor.Inbox.Post(msg, upcast this) type pongActor() as self = let receiver (inbox : MailboxProcessor>) = let rec loop () = async { let! (msg, actor) = inbox.Receive() match msg with | Stop -> printfn "[%d] Pong finished" (tid()) return () | Ping(n) -> printfn "[%d] Pong received ping : %d" (tid()) n self |> send (Pong n) actor return! loop () | _ -> return! loop () } loop () let inbox = MailboxProcessor.Start(receiver) interface IAgent with member this.Inbox = inbox member this.Send(msg, actor) = actor.Inbox.Post(msg, upcast this) let ping = new pingActor() let pong = new pongActor() ping |> send (Ping 3) pong System.Console.ReadLine() |> ignore