Limiti di tipo Nat in Shapeless


151

In informe, il tipo Nat rappresenta un modo per codificare numeri naturali a livello di tipo. Viene utilizzato ad esempio per elenchi di dimensioni fisse. È anche possibile eseguire calcoli a livello di tipo, ad esempio aggiungere un elenco di Nelementi a un elenco di Kelementi e recuperare un elenco che è noto al momento della compilazione per avere N+Kelementi.

Questa rappresentazione è in grado di rappresentare grandi numeri, ad esempio 1000000o 2 53 , o questo farà arrendere il compilatore Scala?


21
La presentazione di Miles NE Scala dell'anno scorso affronta questa domanda, e la risposta breve è che sarebbe possibile rappresentare grandi numeri a livello di tipo in Scala - o almeno in 2.10 - usando tipi singleton , ma potrebbe non valerne la pena . Shapeless 2.0 attualmente utilizza ancora la codifica Church, che ti porterà a circa 1.000 prima che il compilatore si arrenda.
Travis Brown,

3
Proverò a scrivere una risposta con un po 'più contesto più tardi oggi. Come nota a margine , non è troppo difficile lavorare con tipi singleton interi se hai bisogno di numeri di livello di tipo più grandi — vedi ad esempio il mio post sul blog qui o la funzionalità singleton in Shapeless .
Travis Brown,

2
Se si desidera eseguire l'aritmetica su grandi numeri a livello di tipo, è possibile prendere in considerazione l'implementazione come un elenco collegato di bit.
Karol S,

1
@KarolS Ho un'implementazione di quella strategia! E sarei felice di contribuire a informe se qualcuno è interessato, anche se è inutile a meno che qualcuno può aiutare a risolvere stackoverflow.com/questions/31768203/...
beefyhalo

2
Sembra che stackoverflow.com/questions/31768203/… sia risolto, quindi puoi contribuire con il tuo codice e chiudere la domanda con la tua risposta?
Andriy Kuba,

Risposte:


17

Ne proverò uno io stesso. Accetterò volentieri una risposta migliore da Travis Brown o Miles Sabin.

Nat attualmente può non essere utilizzato per rappresentare grandi numeri

Nell'attuale implementazione di Nat, il valore corrisponde al numero di tipi annidati informi.Succ []:

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

Quindi, per rappresentare il numero 1000000, avresti un tipo che è annidato a 1000000 livelli di profondità, che farebbe sicuramente saltare il compilatore scala. Il limite attuale sembra essere di circa 400 dalla sperimentazione, ma per tempi di compilazione ragionevoli sarebbe probabilmente meglio rimanere al di sotto di 50.

Tuttavia, esiste un modo per codificare interi di grandi dimensioni o altri valori a livello di tipo, a condizione che non si desideri eseguire calcoli su di essi . L'unica cosa che puoi fare con quelli per quanto ne so è verificare se sono uguali o meno. Vedi sotto.

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

Questo potrebbe essere usato, ad esempio, per applicare la stessa dimensione di array quando si eseguono operazioni di bit su Array [byte].


Ho appena visto questa risposta e +1, questo è un buon esempio. Vale la pena notare che è possibile fornire classi di tipi come ad esempio Shapeless ops.nat.Sumche potrebbero testimoniare che due numeri interi a livello di tipo avevano una somma particolare, ecc. ( Dovrebbero essere forniti solo da una macro).
Travis Brown

1
Ecco un esempio di una Concatclasse di tipo che consente di concatenare due stringhe a livello di tipo tramite una macro. Una classe di tipo per sommare numeri interi a livello di tipo probabilmente apparirebbe molto simile.
Frank S. Thomas,

5

Shapeless's Natcodifica i numeri naturali a livello di tipo usando la codifica Church. Un metodo alternativo è quello di rappresentare i naturali come un HList di bit di livello di tipo.

Scopri denso che implementa questa soluzione in uno stile informe.

Non ci ho lavorato per un po ', e ha bisogno di una spolverata di' informe ' Lazyqua e là per quando lo scalac si arrende, ma il concetto è solido :)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.