"F# でのテスト用 DSL について考える"で書いたコンピュテーション式

発端や流れに関しては

F# でのテスト用 DSL について考える — a wandering wolf

を読んでください。

本記事では私が実装してみたコンピュテーション式についてゆるく説明します。

先に読むべきもの

詳説コンピュテーション式 - ぐるぐる~

コンピュテーション式の実装にStateを用いる - pocketberserkerの爆走

第1版

https://gist.github.com/pocketberserker/40006f8da7e195924713/092438c92ed1de1cb65809876fdddcd15c2ad401

  • do! で失敗したら移行を実行しない
  • それ以外はとりあえず実行する

みたいな話があったので、ぱっと思いついた Source メソッドを悪用する方針で攻めることにしました。 Source メソッドオーバーロードすることで、unit型かそれ以外の型かをBindメソッドなどに伝えます。

このタイミングはここで時間切れだったので、中途半端な状態で公開しました。

第2版

こういう話と、bleis さんの実装した

TestBuilder.fs

を眺めながらいじったコードが以下になります。

https://gist.github.com/Gab-km/86dd730a8d8e407a699f に触発された何か

Bindメソッドの基本はbleisさんのものを借りつつ、Value に入力型を持たせることで失敗したアサーション以降のアサーションも実行できるようにしました。 Unchecked.defaultof を使っているので危険では?という意見もあるかもしれませんが、 `let! _`` で捨てる前提なので、これでいいかな、と。

第3版

とはいえ、 let! _ はあまりきれいじゃない気がしますし、どうせなら yield! のほうがよさそうだよね、ということでさらにいじりました。

https://gist.github.com/Gab-km/86dd730a8d8e407a699f に触発された何か

過去に紹介した、引数で状態を引き回す方法を使ってCombineを実装することにより、 yield! を連続で呼び出すことが可能です。

Sourceメソッドで注意すべき点

Sourceメソッドはそこそこ変換に現れるので、型合わせるのが簡単ではないです(そこまで難しいわけでもないですが)。

最終版の場合だと、Source メソッドで結果、型情報、状態を生成して型をあわせつつ、YieldFromやReturnFromで状態のみ書き換えるとかしてしのいでいます。

おわりに

実用化?知らない子ですね。