web-dev-qa-db-fra.com

Limites de type Nat dans Shapeless

Dans informe, le type Nat représente un moyen de coder des nombres naturels au niveau du type. Ceci est utilisé par exemple pour les listes de taille fixe. Vous pouvez même faire des calculs au niveau du type, par exemple ajouter une liste d'éléments N à une liste d'éléments K et récupérer une liste qui est connue au moment de la compilation pour avoir N+K éléments.

Cette représentation est-elle capable de représenter de grands nombres, par exemple 1000000 ou 253, ou cela entraînera-t-il l'abandon du compilateur Scala?

150
Rüdiger Klaehn

Je vais en essayer un moi-même. J'accepterai volontiers une meilleure réponse de Travis Brown ou Miles Sabin.

Nat peut actuellement pas être utilisé pour représenter de grands nombres

Dans l'implémentation actuelle de Nat, la valeur correspond au nombre de types imbriqués sans forme.Succ []:

scala> Nat(3)
res10: shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]] = Succ()

Donc, pour représenter le nombre 1000000, vous auriez un type qui est imbriqué à 1000000 niveaux de profondeur, ce qui ferait exploser le compilateur scala. La limite actuelle semble être d'environ 400 par expérimentation, mais pour des temps de compilation raisonnables, il serait probablement préférable de rester en dessous de 50.

Cependant, il existe un moyen de coder de grands nombres entiers ou d'autres valeurs au niveau du type à condition que vous ne vouliez pas faire de calculs sur eux . La seule chose que vous puissiez faire avec ceux que je sache, c'est de vérifier s'ils sont égaux ou non. Voir ci-dessous.

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

Cela pourrait être utilisé pour par exemple appliquer la même taille de tableau lors des opérations de bits sur le tableau [octet].

17
Rüdiger Klaehn

Nat de Shapeless code les nombres naturels au niveau du type en utilisant le codage Church. Une autre méthode consiste à représenter les éléments naturels sous la forme d'une liste de bits de niveau type.

Découvrez dense qui implémente cette solution dans un style informe.

Je n'ai pas travaillé dessus depuis un moment, et il a besoin d'une pincée de 'Lazy informe ici et là quand scalac abandonne, mais le concept est solide :)

5
beefyhalo