无形的Nat类型的限制

时间:2014-01-22 23:15:41

标签: scala numbers compiler-optimization shapeless

在无形状中,Nat类型表示在类型级别编码自然数的方法。这用于例如固定大小的列表。您甚至可以在类型级别进行计算,例如将N元素列表附加到K元素列表中,并返回在编译时已知有N+K个元素的列表。

这种表示能否代表大数字,例如1000000或2 53 ,或者这会导致Scala编译器放弃吗?

2 个答案:

答案 0 :(得分:12)

我会自己尝试一个。我很乐意接受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]上执行位操作时强制执行相同的数组大小。

答案 1 :(得分:2)

无形Nat使用教会编码在类型级编码自然数。另一种方法是将自然表示为比特的类型级HList。

查看dense以无形样式实现此解决方案。

我暂时没有对它进行过工作,它需要一点点无形的&#39; Lazy当scalac放弃时,这里和那里,但概念是坚实的:)