TypeProviderでFizzBuzzを取得可能な自然数型を生成する

コンパイル時に生成できますね、というだけの話です。

準備: FSharp.TypeProviders.StarterPackのインストール

NuGetからインストールしてください。

注意点としては、ファイルの定義順序がそのままだとコンパイルできない可能性があることでしょうか。

  1. ProvidedTypes.fsi
  2. ProvidedTypes.fs
  3. DebugProvidedTypes.fs

コンパイルできるはず。

型を生成してFizzBuzzを取得できるようにする

https://github.com/pocketberserker/MLStudy/commit/9a0a2795d5f8915cab89a5badf65d3abe17b1cf1

FizzBuzz1から100までと範囲が明確に決まっていますが、それでは面白くないので任意の範囲でとれるようにしましょう。 ProvidedStaticParameterでTypeProvider利用時に引数を渡せるようになるとかなんとか。 定義したProvidedStaticParameter群はProvidedTypeDefinition#DefineStaticParametersに渡すことで登録でき、第2引数で生成の操作を記述できます。

λ式内でやっていることは簡単です。

  1. FizzBuzzを計算し
  2. 自然数用の型を定義し
  3. FizzBuzzの結果を取得するプロパティを設定する(今回はFizzBuzzプロパティ)

使う側ではlet inline dump (value: ^n) = (^n: (member FizzBuzz: string) value) |> printfn "%s"という風に静的に解決された型パラメータを用いてFuzzBuzzを持つ値を出力できるようにします。

足し算がしたい

https://github.com/pocketberserker/MLStudy/commit/aee21c03a3d7e804c48e9c2fc13655c459645e40

数値なのに足し算できないのはおかしい、ということで足し算できるようにします。

  1. 数値と型のマッピングをもっておく
  2. 足し算で得た数値の型が存在するならop_Additionメソッドを定義、そうでないなら何もしない

こう改良することで、生成される範囲の自然数型で足し算ができます。 もちろんFizzBuzzも表示できます。

余談

ここで生成した各自然数型は共通するインターフェースを持ちません。 足し算程度ならインターフェースを用意しなくてもオーバーロードでごり押しできます。

発展

この状態ではリストを取得できません。 HListを用いれば良いはずですが、これに関しては読者の課題とします。