継続を利用してAsyncコンピュテーション式を実装できるか試す
Combine Deep Dives - ぐるぐる~ という記事にこういう文章があります。
このあたりを解決するために、Stateを使ったり継続を使ったりできるかもしれませんが、Async では未検証です。
そういえば検証したことはなかったなと思ったので、試してみました。
コード
コンパイルは通るしテストも通る、という代物は下記コードです。 ただし、テストは通ったけれど本当に非同期に動いているかどうかまでは検証していないというレベルです。
Option、Listの実装と異なる部分
OptionやListでの実装は、パターンマッチによって値を分解することで包まれていた値を取り出すことができるのでわりと簡単に実装できていました。
しかしAsync
はパターンマッチで分解できません。
というわけで、とりあえず各メソッドでは関数をAsync
で返すようにします。
そしてRun
メソッドでは値を返したいのでasync.Return
を渡します。
ゼロ値の処遇
今回実装したAsyncBuilder
ではZero
メソッドを提供せず、AsyncWithZeroBuilder
ゼロ値を渡すようにしました。
が、既存のコンピュテーション式よりもAsyncBuilder
の表現力が落ちるためちょっと納得いってません。
本当は「Return
やReturnFrom
が呼び出されなければコンパイルエラー」というビルダークラスを作りたかったのですが、if then ce
というコンピュテーション式の変形においてce
とZero
の型が一致しなければならず、そこを通過しつつRun
メソッドのみコンパイルエラーになるような実装をついに導き出せませんでした…無念。
未検証の作戦として「Run
で返す値をAsync<'T -> Async<'U>>
のままにする」というものがあります。しかし、これはこれでAsync.RunSynchronous
やAsync.Start
などの多くのメソッドをラップする必要があるので悩みどころです。
まとめ
コンピュテーション式について考えると休日が吹き飛ぶの、つらい。