Пределы типа Nat в Shapeless

151

В бесформенном типе Nat представлен способ кодирования натуральных чисел на уровне типа. Это используется, например, для списков фиксированного размера. Вы даже можете выполнять вычисления на уровне типа, например, добавлять список Nэлементов в список Kэлементов и возвращать список, который, как известно, во время компиляции имеет N+Kэлементы.

Способно ли это представление представлять большие числа, например, 1000000или 2 53 , или это заставит компилятор Scala сдаться?

Рюдигер Клаен
источник
21
Презентация Майлза NE Scala в прошлом году посвящена этому вопросу, и краткий ответ состоит в том, что было бы возможно представить большие числа на уровне типов в Scala - или, по крайней мере, в 2.10 - с использованием одноэлементных типов , но это может не стоить этого . Shapeless 2.0 в настоящее время все еще использует кодировку Church, которая даст вам 1000 или около того, прежде чем компилятор сдастся.
Трэвис Браун
3
Я постараюсь написать ответ с чуть большим контекстом позже сегодня. Как примечание стороны, это не слишком трудно работать с целым одноплодными типами , если вам нужно больше уровня типа номера, смотрите, например , мой блог здесь или функциональность одиночки в бесформенном .
Трэвис Браун
2
Если вы хотите выполнять арифметику для больших чисел уровня типа, вы можете рассмотреть возможность их реализации в виде связанного списка битов.
Karol S
1
@KarolS У меня есть реализация этой стратегии! И я был бы рад внести это в бесформенное, если кому-то интересно, хотя это бесполезно, если кто-то не может помочь решить stackoverflow.com/questions/31768203/…
beefyhalo
2
Похоже, что stackoverflow.com/questions/31768203/… решен, так что вы можете добавить свой код и закрыть вопрос своим ответом?
Андрей Куба

Ответы:

17

Я попробую один сам. Я с удовольствием приму лучший ответ от Трэвиса Брауна или Майлза Сабина.

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]
                 ^

Это может быть использовано, например, для обеспечения того же размера массива при выполнении битовых операций над массивом [байт].

Рюдигер Клаен
источник
Только что увидел этот ответ, и +1, это хороший пример. Однако стоит отметить, что вы можете предоставить классы типов, например, Shapeless, ops.nat.Sumкоторые будут свидетельствовать о том, что два целых числа уровня типа имеют определенную сумму и т. Д. (Они просто должны быть предоставлены макросом).
Трэвис Браун
1
Вот пример Concatкласса типов, который позволяет объединить две строки уровня типа через макрос. Класс типов для суммирования целых чисел на уровне типов, вероятно, будет выглядеть очень похоже.
Фрэнк С. Томас
5

Shapeless's Natкодирует натуральные числа на уровне типа, используя кодировку Черча. Альтернативный метод заключается в представлении натуральных чисел в виде HList уровня битов.

Посмотрите плотную, которая реализует это решение в бесформенном стиле.

Я не работал над этим в течение некоторого времени, и он нуждается в небольшом количестве Lazyкапель, когда скалак сдается, но концепция тверда :)

beefyhalo
источник