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:
val addressZipCodeLens = Lens(
get = (_: Address).zipCode,
set = (addr: Address, zipCode: Int) => addr.copy(zipCode = zipCode))
val personAddressLens = Lens(
get = (_: Person).address,
set = (p: Person, addr: Address) => p.copy(address = addr))
Sekarang, buat mereka untuk mendapatkan lensa yang mengubah kode pos dalam diri seseorang:
val personZipCodeLens = personAddressLens andThen addressZipCodeLens
Akhirnya, gunakan lensa itu untuk mengubah raj:
val updatedRaj = personZipCodeLens.set(raj, personZipCodeLens.get(raj) + 1)
Atau, menggunakan gula sintaksis:
val updatedRaj = personZipCodeLens.set(raj, personZipCodeLens(raj) + 1)
Atau bahkan:
val updatedRaj = personZipCodeLens.mod(raj, zip => zip + 1)
Inilah implementasi sederhana, diambil dari Scalaz, digunakan untuk contoh ini:
case class Lens[A,B](get: A => B, set: (A,B) => A) extends Function1[A,B] with Immutable {
def apply(whole: A): B = get(whole)
def updated(whole: A, part: B): A = set(whole, part) // like on immutable maps
def mod(a: A, f: B => B) = set(a, f(this(a)))
def compose[C](that: Lens[C,A]) = Lens[C,B](
c => this(that(c)),
(c, b) => that.mod(c, set(_, b))
)
def andThen[C](that: Lens[B,C]) = that compose this
}