web-dev-qa-db-ja.com

ShapelessのNatタイプの制限

シェイプレスでは、Nat型は型レベルで自然数をエンコードする方法を表します。これは、たとえば固定サイズのリストに使用されます。型レベルで計算することもできます。 N要素のリストにK要素のリストを追加し、コンパイル時にN+K要素を持つことがわかっているリストを取得します。

この表現は、大きな数字を表現できますか? 1000000または253、またはこれによりScalaコンパイラがgiveめますか?

149
Rüdiger Klaehn

自分で試してみます。 Travis BrownまたはMiles Sabinからのより良い回答を喜んで受け入れます。

Natは現在notを使用して大きな数を表すことができます

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]でビット演算を行うときに同じ配列サイズを強制します。

14
Rüdiger Klaehn

ShapelessのNatは、Churchエンコーディングを使用して、タイプレベルで自然数をエンコードします。別の方法は、自然をビットのタイプレベルHListとして表すことです。

dense をチェックしてください。これは、このソリューションを形のないスタイルで実装します。

私はしばらく作業していないので、スカラックがgivesめたときのために、あちこちに無形のLazyを振りかける必要がありますが、コンセプトはしっかりしています:)

4
beefyhalo