7
votes

Comment puis-je extraire des classes de cas remplies d'options dans Scala

Je suis très nouveau à Scala et j'essaie toujours de m'habituer à la syntaxe et à la style, c'est probablement une question très simple.

Je travaille avec une base de code où il y a beaucoup de cas classes remplies d'options telles que: xxx

dans l'exemple ci-dessus, comment allez-vous retourner combien d'argent est dans une personne ' Code> Pantalon Pocket , S'ils portent des pantalons ... avec des poches, et s'ils ont de l'argent du tout?


0 commentaires

4 Réponses :


8
votes

Un bon moment pour pour les compréhensions : < Pré> xxx

Equivalement Vous pouvez écrire ce qui suit, pour lequel le premier code est syntaxique sucre (ignorant certaines subtilités): xxx

(je suis Pas totalement sûr si vous pouvez écrire la dernière expression à l'aide des caractères génériques _ , comme je l'ai fait).


1 commentaires

Super merci! L'approche de compréhension est en fait exactement ce que j'essayais de faire, mais la structure que je travaille n'est pas aussi propre que l'exemple que j'ai donné ci-dessus. Au moins cela confirme que je suis sur la bonne voie.



2
votes

La réponse de Ziggystar est ce que j'utiliserais, mais pour l'exhaustivité, la correspondance des motifs peut également être utilisée, par exemple

val someCash: Option[Cash] = person match {
  case Person(Some(Pants(Some(Pocket(Some(cash)))))) => Some(cash)
  case _ => None
}


0 commentaires

6
votes

La question ne mentionnait pas modifier em> les données, mais lorsque vous devez le faire, vous trouverez rapidement la bibliothèque Scala ne dispose pas des outils pour faciliter la tâche (lorsque les données sont immuables) . Si vous n'avez pas encore vécu cela, essayez d'écrire une fonction qui remplacera ou modifiera la valeur code> du en espèces code> détenu par un personne code> , en utilisant les types définis dans la question.

comme décrit dans Tony Morris ' Objectifs asymétriques à Scala , lentilles em> sont une solution appropriée à ce problème. P>

Voici un exemple de la manière dont nous pouvons accéder à l'accès et à la mise à jour de la valeur code> code> d'une personne en espèces code> à l'aide de la lentille code> et Plens code> (objectif partiel) des implémentations de Scalaz-Seven Branche de Scalaz. P>

Premier, certains chaudières: définir l'instance de lentille pour chaque champ des classes de boîtier. A @ - @ b code> signifie identique à objectif [A, B] code>. p> xxx pré>

Nous ne pouvons pas composer toutes ces lentilles, cependant, parce que la plupart des champs sont enveloppés dans les types code> (code> (code> p>

lentilles partielles em> à la rescousse: celles-ci nous permettent d'accéder à et mettre à jour les parties d'une structure qui peut ne pas exister em>, telle que la valeur une valeur code> d'une option code> ou de la tête ou de la tête code > d'une liste code> code>. p>

Nous pouvons utiliser la fonction code> à pied code> de Scalaz 7 pour créer une lentille partielle visualisant chaque champ facultatif. Afin de composer une lentille partielle avec l'une de nos objectifs ordinaires, nous devons toutefois accéder à l'instance d'objectif partielle équivalente pour la lentille ordinaire, à l'aide de la méthode partielle code> sur chaque lentille .

scala> val ben = Person(None)
ben: Person = Person(None)

scala> someCashValue.mod(_ + ", zero, nada", ben)
res4: Person = Person(None)


0 commentaires

12
votes

Scalaz 7 a changé un peu donc ici est un autre exemple:

  object PartialLensExample extends App {

  import scalaz._
  import Lens._
  import PLens._


  case class Bar(blub: Option[String])
  case class Foo(bar: Option[Bar])

  // normal lenses for getting and setting values
  val fooBarL: Foo @> Option[Bar] = lensg(foo ⇒ bar ⇒ foo.copy(bar = bar), _.bar)
  val barBlubL: Bar @> Option[String] = lensg(bar ⇒ blub ⇒ bar.copy(blub = blub), _.blub)

  // compose the above as 'Partial Lenses', >=> is just an alias for 'andThen'
  val fooBarBlubL: Foo @?> String = fooBarL.partial >=> somePLens >=> barBlubL.partial >=> somePLens

  // try it
  val foo = Foo(Some(Bar(Some("Hi"))))

  println(fooBarBlubL.get(foo)) // Some(Hi)

  println(fooBarBlubL.set(foo, "Bye")) //Foo(Some(Bar(Some(Bye))))

  // setting values
  val foo2 = Foo(None)
  println(fooBarL.set(foo2, Some(Bar(None)))) // Foo(Some(Bar(None)))

}


4 commentaires

Une bonne réponse, mais une grosse trottoir ici lors de la définition de ces valeurs imbriquées est la suivante: que si des valeurs sont Aucun ? Le Plens dans votre exemple n'autorisera que Blub: option [string] à attribuer si blub a déjà certains < / Code> Valeur . J'ai trouvé des transitions d'état monadiques peut initialiser les membres de niveau supérieur, mais je ne suis pas clair comment cela serait fait pour les personnes plus bas.


hmm, oui. J'ai mis à jour la réponse pour la définition d'une barre sur une FOO, mais je vois la question de la définition de la valeur de Blub dans la barre - je devrai réfléchir à ce sujet.


A Bogosity des transitions d'état en utilisant Plens instances est le mieux que je pouvais Faites, initialisez les propriétés selon les besoins (ce qui est logique, surtout à la lumière de La réponse impliquant des pantalons @ Ben-James a donné). Cela me frappe comme trop laborieux et ça n'a pas échoué, alors j'imagine qu'il y a une meilleure approche.


Après avoir réfléchi à cela, je pense que le comportement est correct tel qu'il est. Ce problème se résume à une lentille définissant une valeur sur une option. Si l'option n'en est pas, il n'y a rien à définir. Cependant, je peux également voir qu'il serait utile pour une lentille de prendre en charge la définition d'une valeur dans une option contenue par un autre type, comme un raccourci peut-être. Comme il est debout, vous devez définir l'option dans son ensemble.