Zabawne, że nikt nie dodał soczewek, ponieważ zostały stworzone do tego typu rzeczy. Więc tutaj jest tło papieru CS na nim, tutaj jest blog, który na krótko dotykowy obiektywów używać w Scala, tutaj jest realizacja soczewki dla Scalaz i tutaj jest jakiś kod używając go, co wygląda zaskakująco podobne pytanie. I, aby zmniejszyć liczbę kotłów, oto wtyczka, która generuje soczewki Scalaz dla klas przypadków.
Jeśli chodzi o punkty dodatkowe, oto kolejne pytanie SO, które dotyczy soczewek i artykuł Tony'ego Morrisa.
Najważniejsze w soczewkach jest to, że można je komponować. Na początku są trochę uciążliwe, ale im częściej ich używasz, zyskują na popularności. Ponadto są świetne do testowania, ponieważ wystarczy przetestować pojedyncze soczewki i można przyjąć ich skład za pewnik.
Tak więc, w oparciu o implementację podaną na końcu tej odpowiedzi, oto jak to zrobić z soczewkami. Najpierw zadeklaruj soczewki do zmiany kodu pocztowego w adresie i adresu w osobie:
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))
Teraz utwórz je, aby uzyskać soczewkę, która zmienia kod pocztowy w osobie:
val personZipCodeLens = personAddressLens andThen addressZipCodeLens
Na koniec użyj tego obiektywu, aby zmienić raj:
val updatedRaj = personZipCodeLens.set(raj, personZipCodeLens.get(raj) + 1)
Lub używając cukru syntaktycznego:
val updatedRaj = personZipCodeLens.set(raj, personZipCodeLens(raj) + 1)
Lub nawet:
val updatedRaj = personZipCodeLens.mod(raj, zip => zip + 1)
Oto prosta implementacja, zaczerpnięta ze Scalaz, użyta w tym przykładzie:
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
}