Katakanlah saya sudah mengikuti dua case class
es:
case class Address(street: String, city: String, state: String, zipCode: Int)
case class Person(firstName: String, lastName: String, address: Address)
dan instance Person
kelas berikut :
val raj = Person("Raj", "Shekhar", Address("M Gandhi Marg",
"Mumbai",
"Maharashtra",
411342))
Sekarang jika saya ingin memperbarui zipCode
dari raj
maka saya akan harus melakukan:
val updatedRaj = raj.copy(address = raj.address.copy(zipCode = raj.address.zipCode + 1))
Dengan lebih banyak tingkat bersarang ini menjadi lebih buruk. Apakah ada cara yang lebih bersih (seperti milik Clojure update-in
) untuk memperbarui struktur bersarang seperti itu?
scala
case-class
zipper
missingfaktor
sumber
sumber
Jawaban:
Resleting
Huet's Zipper memberikan traversal yang nyaman dan 'mutasi' dari struktur data yang tidak berubah. Scalaz menyediakan Ritsleting untuk
Stream
( scalaz.Zipper ), danTree
( scalaz.TreeLoc ). Ternyata struktur ritsleting secara otomatis dapat diturunkan dari struktur data asli, dengan cara yang menyerupai diferensiasi simbolis dari ekspresi aljabar.Tetapi bagaimana ini membantu Anda dengan kelas kasus Scala Anda? Nah, Lukas Rytz baru-baru ini membuat prototipe ekstensi untuk scalac yang secara otomatis akan membuat ritsleting untuk kelas kasus beranotasi. Saya akan mereproduksi contohnya di sini:
Jadi masyarakat perlu meyakinkan tim Scala bahwa upaya ini harus dilanjutkan dan diintegrasikan ke dalam penyusun.
Kebetulan, Lukas baru-baru ini menerbitkan versi Pacman, pengguna yang dapat diprogram melalui DSL. Namun, sepertinya dia tidak menggunakan kompiler yang dimodifikasi, karena saya tidak dapat melihat
@zip
anotasi.Penulisan Ulang Pohon
Dalam keadaan lain, Anda mungkin ingin menerapkan beberapa transformasi di seluruh struktur data, sesuai dengan beberapa strategi (top-down, bottom-up), dan berdasarkan aturan yang cocok dengan nilai di beberapa titik dalam struktur. Contoh klasik adalah mengubah AST untuk bahasa, mungkin untuk mengevaluasi, menyederhanakan, atau mengumpulkan informasi. Kiama mendukung Penulisan Ulang , lihat contoh di RewriterTests , dan tonton video ini . Berikut cuplikan untuk membangkitkan selera Anda:
Perhatikan bahwa Kiama melangkah keluar dari sistem tipe untuk mencapai ini.
sumber
Lucu tidak ada yang menambahkan lensa, karena mereka DIBUAT untuk hal semacam ini. Jadi, di sini adalah kertas latar belakang CS di atasnya, di sini adalah blog yang menyentuh sebentar tentang penggunaan lensa di Scala, di sini adalah implementasi lensa untuk Scalaz dan di sini ada beberapa kode yang menggunakannya, yang secara mengejutkan tampak seperti pertanyaan Anda. Dan, untuk mengurangi pelat ketel, inilah plugin yang menghasilkan lensa Scalaz untuk kelas kasus.
Untuk poin bonus, inilah pertanyaan SO lainnya yang menyentuh lensa, dan kertas karya Tony Morris.
Masalah besar tentang lensa adalah mereka dapat dikomposit. Jadi mereka agak rumit pada awalnya, tetapi mereka terus mendapatkan tanah semakin Anda menggunakannya. Selain itu, lensa ini sangat bagus untuk pengujian, karena Anda hanya perlu menguji masing-masing lensa, dan dapat menerima begitu saja komposisi mereka.
Jadi, berdasarkan implementasi yang disediakan di akhir jawaban ini, inilah cara Anda melakukannya dengan lensa. Pertama, nyatakan lensa untuk mengubah kode pos di alamat, dan alamat di seseorang:
Sekarang, buat mereka untuk mendapatkan lensa yang mengubah kode pos dalam diri seseorang:
Akhirnya, gunakan lensa itu untuk mengubah raj:
Atau, menggunakan gula sintaksis:
Atau bahkan:
Inilah implementasi sederhana, diambil dari Scalaz, digunakan untuk contoh ini:
sumber
personZipCodeLens.set(raj, personZipCodeLens.get(raj) + 1)
ini sama denganpersonZipCodeLens mod (raj, _ + 1)
mod
bukan primitif untuk lensa.Alat yang berguna untuk menggunakan Lensa:
Hanya ingin menambahkan bahwa makrokosmos dan Rillit proyek, berdasarkan Scala 2.10 macro, menyediakan Dinamis Penciptaan Lensa.
Menggunakan Rillit:
Menggunakan Macrocosm:
sumber
Saya telah mencari-cari perpustakaan Scala yang memiliki sintaksis terbaik dan fungsi terbaik dan satu perpustakaan yang tidak disebutkan di sini adalah monocle yang bagi saya sangat bagus. Contoh berikut:
Ini sangat bagus dan ada banyak cara untuk menggabungkan lensa. Scalaz misalnya membutuhkan banyak boilerplate dan ini mengkompilasi dengan cepat dan berjalan dengan baik.
Untuk menggunakannya dalam proyek Anda cukup tambahkan ini ke dependensi Anda:
sumber
Tak berbentuk melakukan trik:
dengan:
Perhatikan bahwa sementara beberapa jawaban lain di sini memungkinkan Anda menyusun lensa untuk masuk lebih dalam ke dalam struktur yang diberikan lensa tak berbentuk ini (dan perpustakaan / makro lain) memungkinkan Anda menggabungkan dua lensa yang tidak terkait sehingga Anda dapat membuat lensa yang menetapkan jumlah parameter yang berubah-ubah menjadi posisi acak. dalam struktur Anda. Untuk struktur data yang kompleks komposisi tambahan itu sangat membantu.
sumber
Lens
kode dalam jawaban Daniel C. Sobral dan karenanya menghindari menambahkan ketergantungan eksternal.Karena sifat komposisinya, lensa memberikan solusi yang sangat bagus untuk masalah struktur bersarang. Namun dengan tingkat sarang yang rendah, saya terkadang merasa lensa terlalu banyak, dan saya tidak ingin memperkenalkan pendekatan seluruh lensa jika hanya ada beberapa tempat dengan pembaruan bersarang. Demi kelengkapan, berikut adalah solusi yang sangat sederhana / pragmatis untuk kasus ini:
Apa yang saya lakukan adalah hanya menulis beberapa
modify...
fungsi pembantu di struktur tingkat atas, yang berurusan dengan salinan bersarang jelek. Misalnya:Tujuan utama saya (menyederhanakan pembaruan di sisi klien) tercapai:
Membuat set lengkap pembantu modifikasi jelas menjengkelkan. Tetapi untuk hal-hal internal seringkali cukup baik untuk membuatnya saat pertama kali Anda mencoba memodifikasi bidang bersarang tertentu.
sumber
Mungkin QuickLens cocok dengan pertanyaan Anda dengan lebih baik. QuickLens menggunakan makro untuk mengubah ekspresi ramah IDE menjadi sesuatu yang dekat dengan pernyataan salin asli.
Diberikan dua contoh kelas kasus:
dan instance dari kelas Person:
Anda dapat memperbarui kode pos raj dengan:
sumber