async周りのメモ

MSDN マガジンのバックナンバーがとてもよい入門になっている気がするので、メモ。

簡単な束縛式

> let x = async{return 1};;

val x : Async<int>

を見てやると、xはAsyncで束縛されていることがわかる。これを使ってまた別な束縛を行おうとすると・・・

> let y = async{
    let res = x
    return res + 5
};;

      return res + 5
  -----------------^

\stdin(20,18): error FS0001: The type 'int' does not match the type 'Async<int>'

というように、int型とAsyncは違うので足すことができないというエラーメッセージが返ってくる。
この時、let束縛ではなくlet!(レット・バン?と読むのか?)を使うと

> let y = async{
    let! res = x
    return res + 5
};;

val y : Async<int>

として計算を進めることができる。これをAsync.RunSynchronouslyを使って実行してみると・・・

> Async.RunSynchronously y;;
val it : int = 6

となって、ちゃんと求めるべき6という数値が返ってくる。今の場合、値を足しこむ処理を行ったが、そのまま返す場合にはreturn!を使えばよい。これはlet!を使っても当然書けるが、return!を使ったほうが短く記述することができる。

> let y = async{return! x};;

val y : Async<int>

> let y = async{
    let! hoge = x
    return hoge
};;

val y : Async<int>

非同期に配列の各要素に対して計算を回したいときはArray.Parallelを組み合わせる。

> let nums = [|async{return 1 + 1}; async{return 1 + 2}; async{return 1 + 3}|];;

val nums : Async<int> [] =
  [|Microsoft.FSharp.Control.FSharpAsync`1[System.Int32];
    Microsoft.FSharp.Control.FSharpAsync`1[System.Int32];
    Microsoft.FSharp.Control.FSharpAsync`1[System.Int32]|]

> Async.RunSynchronously nums;;

  Async.RunSynchronously nums;;
  -----------------------^^^^

C:\Users\yana\AppData\Local\Temp\stdin(42,24): error FS0001: This expression was expected to have type
    Async<'a>    
but here has type
    Async<int> []    
> Async.RunSynchronously (Async.Parallel nums);;
val it : int [] = [|2; 3; 4|]

Async.Parallel自体はAsyncの配列をAsync(int配列のAsync)へと直してくれているようだ。

> Async.Parallel nums;;
val it : Async<int []> =
  Microsoft.FSharp.Control.FSharpAsync`1[System.Int32[]]