Cela pourrait être fait avec objectifs . L'idée même d'une lentille est de pouvoir zoomer sur une partie particulière d'une structure immuable, et de pouvoir 1) récupérer la petite partie d'une structure plus grande, ou 2) créer une nouvelle structure plus grande avec une petite partie modifiée. Dans ce cas, ce que vous souhaitez, c'est le point 2.
Tout d'abord, une mise en œuvre simple de Lens
volé à cette réponse volé à scalaz :
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
}
Ensuite, un constructeur intelligent pour créer une lentille à partir d'une "structure plus grande". Map[A,B]
à "partie inférieure". Option[B]
. Nous indiquons quelle "petite partie" nous voulons regarder en fournissant une clé particulière. (Inspiré par ce dont je me souviens de Présentation d'Edward Kmett sur les lentilles en Scala ) :
def containsKey[A,B](k: A) = Lens[Map[A,B], Option[B]](
get = (m:Map[A,B]) => m.get(k),
set = (m:Map[A,B], opt: Option[B]) => opt match {
case None => m - k
case Some(v) => m + (k -> v)
}
)
Maintenant, votre code peut être écrit :
val m2 = containsKey("Mark").mod(m)(_.map(_ - 50))
n.b. J'ai en fait changé mod
de la réponse à laquelle je l'ai volée pour qu'elle prenne ses entrées au curry. Cela permet d'éviter les annotations de type supplémentaires. Notez également _.map
parce que n'oubliez pas que notre objectif est de Map[A,B]
a Option[B]
. Cela signifie que la carte sera inchangée si elle ne contient pas la clé "Mark"
. Sinon, cette solution finit par être très similaire à la solution adjust
solution présentée par Travis.