Batas tipe Nat dalam Bentuk

151

Dalam tak berbentuk, tipe Nat mewakili cara untuk menyandikan bilangan asli pada tingkat tipe. Ini digunakan misalnya untuk daftar ukuran tetap. Anda bahkan dapat melakukan perhitungan pada tingkat jenis, misalnya menambahkan daftarN elemen ke daftar Kelemen dan mendapatkan kembali daftar yang diketahui pada waktu kompilasi untuk memiliki N+Kelemen.

Apakah representasi ini mampu mewakili angka besar, misalnya 1000000atau 2 53 , atau akankah ini menyebabkan kompilator Scala menyerah?

Rüdiger Klaehn
sumber
21
Presentasi NE Scala Miles tahun lalu menjawab pertanyaan ini, dan jawaban singkatnya adalah mungkin untuk merepresentasikan angka besar pada level tipe di Scala — atau setidaknya dalam 2,10 — menggunakan tipe singleton , tetapi mungkin tidak sepadan . Shapeless 2.0 saat ini masih menggunakan pengkodean Gereja, yang akan membuat Anda mencapai 1.000 atau lebih sebelum kompiler menyerah.
Travis Brown
3
Saya akan mencoba menulis jawaban dengan konteks yang lebih sedikit hari ini. Sebagai catatan, tidak terlalu sulit untuk bekerja dengan tipe integer singleton jika Anda membutuhkan nomor level tipe yang lebih besar — ​​lihat misalnya posting blog saya di sini atau fungsionalitas singleton di Shapeless .
Travis Brown
2
Jika Anda ingin melakukan aritmatika pada angka tingkat tipe besar, Anda dapat mempertimbangkan menerapkannya sebagai daftar bit yang ditautkan.
Karol S
1
@ KarolS Saya punya implementasi dari strategi itu! Dan saya akan dengan senang hati berkontribusi untuk tidak berbentuk jika ada yang tertarik, meskipun tidak ada gunanya kecuali seseorang dapat membantu memecahkan stackoverflow.com/questions/31768203/…
beefyhalo
2
Sepertinya stackoverflow.com/questions/31768203/... sudah terpecahkan, jadi bisakah Anda menyumbangkan kode dan menutup pertanyaan dengan jawaban Anda sendiri?
Andriy Kuba

Jawaban:

17

Saya akan mencoba satu sendiri. Saya dengan senang hati akan menerima jawaban yang lebih baik dari Travis Brown atau Miles Sabin.

Nat saat ini tidak bisa dapat digunakan untuk mewakili jumlah besar

Dalam implementasi Nat saat ini, nilainya sesuai dengan jumlah tipe nested tak berbentuk. Succ []:

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

Jadi untuk mewakili angka 1000000, Anda akan memiliki tipe yang bersarang level 1000000, yang pasti akan meledakkan kompiler scala. Batas saat ini tampaknya sekitar 400 dari percobaan, tetapi untuk waktu kompilasi yang masuk akal mungkin akan lebih baik untuk tetap di bawah 50.

Namun, ada cara untuk menyandikan bilangan bulat besar atau nilai lain di tingkat tipe, asalkan Anda tidak ingin melakukan perhitungan pada mereka . Satu-satunya hal yang dapat Anda lakukan dengan mereka sejauh yang saya tahu adalah untuk memeriksa apakah mereka sama atau tidak. Lihat di bawah.

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

Ini dapat digunakan untuk misalnya menegakkan ukuran array yang sama ketika melakukan operasi bit pada Array [Byte].

Rüdiger Klaehn
sumber
Baru saja melihat jawaban ini, dan +1, ini adalah contoh yang bagus. Perlu dicatat bahwa Anda dapat memberikan kelas tipe seperti misalnya Shapeless's ops.nat.Sumyang akan menyaksikan bahwa dua bilangan bulat tipe memiliki jumlah tertentu, dll. (Mereka hanya harus disediakan oleh makro).
Travis Brown
1
Berikut adalah contoh Concatkelas tipe yang memungkinkan untuk menggabungkan dua tipe-string melalui makro. Kelas tipe untuk menjumlahkan bilangan bulat tipe-tingkat mungkin akan terlihat sangat mirip.
Frank S. Thomas
5

Shapeless Natmengkodekan bilangan asli pada level tipe menggunakan pengkodean Gereja. Metode alternatif adalah untuk mewakili naturals sebagai tipe tingkat HList bit.

Lihatlah padat yang mengimplementasikan solusi ini dalam gaya tak berbentuk.

Saya belum mengerjakannya dalam beberapa saat, dan perlu taburan tak berbentuk ' Lazydi sana-sini ketika scalac menyerah, tetapi konsepnya solid :)

beefyhalo
sumber