Пределы типа Nat в бесформенном

151

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

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

  • 20
    Презентация Майлза NE Scala в прошлом году посвящена этому вопросу, и короткий ответ заключается в том, что было бы возможно представить большие числа на уровне типов в Scala - или, по крайней мере, в 2.10 - с использованием одноэлементных типов , но это может не стоить этого . Shapeless 2.0 в настоящее время все еще использует кодировку Church, которая даст вам 1000 или около того, прежде чем компилятор сдастся.
  • 0
    Благодарю. Если вы разместите это как ответ, я отмечу это как ответ. Мне нужно будет найти другой способ сделать то, что я хочу сделать.
Показать ещё 5 комментариев
Теги:
numbers
compiler-optimization
shapeless

2 ответа

12
Лучший ответ

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

В настоящее время Nat может не использоваться для представления больших чисел

В текущей реализации Nat это значение соответствует количеству вложенных бесформенных типов .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].

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

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

Отъезд dense, который реализует это решение в бесформенном стиле.

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню