無形の場合、Nat型は、型レベルで自然数をエンコードする方法を表します。これは、たとえば固定サイズのリストに使用されます。タイプレベルで計算を行うこともできます。たとえば、N
要素のリストに要素のリストを追加し、K
コンパイル時にN+K
要素があることがわかっているリストを取得します。
この表現は、たとえば1000000
2または53のような大きな数を表すことができますか、それともScalaコンパイラーが諦めることになりますか?
無形の場合、Nat型は、型レベルで自然数をエンコードする方法を表します。これは、たとえば固定サイズのリストに使用されます。タイプレベルで計算を行うこともできます。たとえば、N
要素のリストに要素のリストを追加し、K
コンパイル時にN+K
要素があることがわかっているリストを取得します。
この表現は、たとえば1000000
2または53のような大きな数を表すことができますか、それともScalaコンパイラーが諦めることになりますか?
回答:
自分でやってみます。Travis BrownまたはMiles Sabinからのより良い回答を喜んで受け入れます。
現在、Natを使用して多数を表すことはできません
Natの現在の実装では、値はネストされたshapeless.Succ []タイプの数に対応します。
scala> Nat(3)
res10: shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]] = Succ()
したがって、1000000という数値を表すには、1000000レベルの深さでネストされた型があり、これは間違いなくScalaコンパイラーを爆破します。現在の制限は実験から約400のようですが、妥当なコンパイル時間のためには、おそらく50未満に留まるのが最善でしょう。
ただし、大きな整数やその他の値をタイプレベルでエンコードする方法があります。ただし、それらについて計算を実行したくない場合に限ります。私が知る限り、それらを使用してできることは、それらが等しいかどうかを確認することだけです。下記参照。
scala> type OneMillion = Witness.`1000000`.T
defined type alias OneMillion
scala> type AlsoOneMillion = Witness.`1000000`.T
defined type alias AlsoOneMillion
scala> type OneMillionAndOne = Witness.`1000001`.T
defined type alias OneMillionAndOne
scala> implicitly[OneMillion =:= AlsoOneMillion]
res0: =:=[OneMillion,AlsoOneMillion] = <function1>
scala> implicitly[OneMillion =:= OneMillionAndOne]
<console>:16: error: Cannot prove that OneMillion =:= OneMillionAndOne.
implicitly[OneMillion =:= OneMillionAndOne]
^
これは、たとえばArray [Byte]でビット操作を行うときに同じ配列サイズを強制するために使用できます。
ops.nat.Sum
(それらはマクロによって提供される必要があるだけです)。
Concat
マクロを介して2つの型レベルの文字列を連結できる型クラスの例です。型レベルの整数を合計するための型クラスは、おそらく非常によく似ています。