C#の非同期プログラミングモデル(APM)をF#のMailboxProcessorに書き換えてみた

非同期処理が得意になりたいなぁと思います、最近。

プログラミング.NET FRAMEWORK 第3版 (Microsoft Press)の27章にAPM(Asynchronous Programming Model)のいい例が載っていたので、勉強がてらF#のMailboxProcessorに書き換えてみました。
例のプログラムがやっていることは、名前つきパイプを使ってクライアントからのリクエストを受け付けて大文字にして返すというもの。

C# : 本に載っているほぼそのまま

class PipeServer{
private readonly NamedPipeServerStream m_pipe =
new NamedPipeServerStream("Echo", PipeDirection.InOut, -1,
PipeTransmissionMode.Message, PipeOptions.Asynchronous | PipeOptions.WriteThrough);

public PipeServer()
{
m_pipe.BeginWaitForConnection(ClientConected, null);
}

private void ClientConected(IAsyncResult result)
{
new PipeServer();

m_pipe.EndWaitForConnection(result);
var data = new Byte[1000];
m_pipe.BeginRead(data, 0, data.Length, GotRequest, data);
}

private void GotRequest(IAsyncResult result)
{
var bytesRead = m_pipe.EndRead(result);
var data = (Byte[]) result.AsyncState;
data = Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(data, 0, bytesRead).ToUpper().ToCharArray());
m_pipe.BeginWrite(data, 0, data.Length, WriteDone, null);
}

private void WriteDone(IAsyncResult result)
{
m_pipe.EndWrite(result);
m_pipe.Close();
}
}

class Program{
static void Main(string[] args)
{
for (var n = 0; n < Environment.ProcessorCount; n++)
{
new PipeServer();
}

Console.WriteLine("Press <Enter> to terminate this server application.");
Console.ReadLine();
}
}

F# : 上のコードと意味的には同じことをしている

open System
open System.IO.Pipes
open System.Text

let pipeServer =
MailboxProcessor.Start(fun inbox ->
let rec
loop() = async {
do! inbox.Receive()
use pipe =
new NamedPipeServerStream(
"Echo", PipeDirection.InOut, -1,
PipeTransmissionMode.Message, PipeOptions.Asynchronous ||| PipeOptions.WriteThrough)

do! Async.FromBeginEnd(pipe.BeginWaitForConnection, pipe.EndWaitForConnection)

inbox.Post()

let data = Array.zeroCreate<byte> 1000
let! bytesRead = Async.FromBeginEnd(data, 0, data.Length, pipe.BeginRead, pipe.EndRead)

let data = Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(data, 0, bytesRead).ToUpper().ToCharArray())
do! Async.FromBeginEnd(data, 0, data.Length, pipe.BeginWrite, pipe.EndWrite)

return! loop()
}
loop() )

let main =
for n in 1 .. Environment.ProcessorCount do
pipeServer.Post()

MailboxProcessorには可能性を感じるなぁ。