Marrant que personne n'a ajouté des lentilles, depuis qu'ils ont FAIT pour ce genre de trucs. Donc, ici, est une CS de fond de papier sur elle, ici est un blog qui touche brièvement sur les lentilles de l'utilisation de Scala, ici, est une des lentilles de mise en œuvre de Scalaz et ici est un code en utilisant, qui ressemble étonnamment à votre question. Et, pour couper vers le bas sur la plaque de la chaudière, voici un plugin qui génèrent Scalaz lentilles pour des classes de cas.
Pour les points de bonus, voici un autre S. O. question qui touche à lentilles, et un papier par Tony Morris.
Le gros problème sur les lentilles, c'est qu'ils sont composables. Ils sont donc un peu lourd au début, mais ils continuent de gagner du terrain le plus vous les utilisez. Aussi, ils sont parfaits pour la testabilité, puisque vous n'avez besoin de tester des lentilles individuelles, et peut tenir pour acquis leur composition.
Donc, basé sur une mise en œuvre à la fin de cette réponse, voici comment vous pouvez le faire avec des lentilles. Tout d'abord, déclarer des lentilles pour changer un code postal d'une adresse, et une adresse à une personne:
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))
Maintenant, pour les composer pour obtenir un objectif que les changements de code postal dans une personne:
val personZipCodeLens = personAddressLens andThen addressZipCodeLens
Enfin, l'utilisation de cet objectif de changement raj:
val updatedRaj = personZipCodeLens.set(raj, personZipCodeLens.get(raj) + 1)
Ou, à l'aide de certaines sucre syntaxique:
val updatedRaj = personZipCodeLens.set(raj, personZipCodeLens(raj) + 1)
Ou encore:
val updatedRaj = personZipCodeLens.mod(raj, zip => zip + 1)
Voici la simple mise en œuvre, la prise de Scalaz, utilisé pour cet exemple:
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
}