Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I pull apart Case Classes filled with Options in Scala

I'm very new to Scala and I'm still trying to get used to the syntax and style, so this is probably a very simple question.

I'm working with a codebase where there are lots of case classes populated with Options like so:

case class Person(
  pants: Option[Pants]
)
case class Pants(
  pocket: Option[Pocket]
)
case class Pocket(
  cash: Option[Cash]
)
case class Cash(
  value: String = "zilch"
)

In the example above, how would you go about returning how much money is in a Person's Pants Pocket, if they are indeed wearing pants... with pockets, and if they have any money at all?

like image 776
Adam Fraser Avatar asked Jan 20 '12 15:01

Adam Fraser


2 Answers

Scalaz 7 has changed a little so here is another example:

  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)))

}
like image 113
Channing Walton Avatar answered Sep 30 '22 14:09

Channing Walton


A great time for for-comprehensions:

val someCash: Option[Cash] =
   for( pants  <- somePerson.pants;
        pocket <- pants.pocket;
        cash   <- pocket.cash ) yield cash

Equivalently you can write the following, for which the first code is syntactic sugar (ignoring some subtleties):

val someCash: Option[Cash] = 
   somePerson.pants.flatMap(_.pocket.flatMap(_.cash))

(I'm not totally sure if you can write the last expression using the _ wildcards, as I did).

like image 28
ziggystar Avatar answered Sep 30 '22 14:09

ziggystar