在 shapeless 中,Nat 类型代表了一种在类型级别对自然数进行编码的方法。例如,这用于固定大小的列表。您甚至可以在类型级别上进行计算,例如将N
元素列表附加到元素列表K
并返回在编译时已知具有N+K
元素的列表。
这种表示是否能够表示大数,例如1000000
2 53,还是会导致 Scala 编译器放弃?
在 shapeless 中,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] 进行位操作时强制使用相同的数组大小。
ShapelessNat
使用 Church 编码在类型级别对自然数进行编码。另一种方法是将自然表示为位的类型级别 HList。
查看以无形样式实现此解决方案的密集。
Lazy
我有一段时间没有研究它了,当 scalac 放弃时,它需要在这里和那里洒一些无形的,但这个概念是可靠的:)