Skip to content

Instantly share code, notes, and snippets.

@kwiest
Last active September 22, 2017 23:55
Show Gist options
  • Save kwiest/986bfe832718726f7ccba6d86e915dd1 to your computer and use it in GitHub Desktop.
Save kwiest/986bfe832718726f7ccba6d86e915dd1 to your computer and use it in GitHub Desktop.
Understanding flatMap and for comprehentions
// Options can be one of 2 things: Something (Some) or nothing (None)
// Because it is "collection" of 2 outcomes, you can iterate using `map`
// Define a function to pass around that uppercases a String or Char
val up : (Any) => Any = (item) => {
item match {
case item: String => item.toUpperCase
case item: Char => Char.toUpperCase(item)
}
}
// val up = Any => Any
maybeKyle : Option[String] = Some("kyle")
maybeKyle.map(up)
// Some("KYLE")
maybeHeron : Option[String] = None
maybeHeron.map(up)
// None
// If we want a tuple of 2 people and it shouldn't exist without one or the other, we can map over each
maybeKyle.map { kyle =>
match kyle {
case Some(name) => maybeHeron.map { heron =>
match heron {
case Some(name) => (kyle, heron)
case None => None
}
}
case None => None
}
}
// Option[(Option[String], Option[String])] = None
// Obviously, the nesting can get deep and messy if you added a 3rd person, or a type that had more than 2 cases.
// `flatMap` smashes these cases down to only expose the case when Some exists
maybeKyle.flatMap { kyle =>
maybeHeron.map { heron =>
(kyle, heron)
}
}
// Option[(Option[String], Option[String])] = None
// Scala also has `for` comprehensions for iterating over a colletion.
// You can assign temporary values in the iteration with `<-` and the loop exits when the right side runs out.
def listNums (n : Int) : Unit = {
for (
i <- 0 until n
) yield print(i + " ")
}
listNums(10)
// 0 1 2 3 4 5 6 7 8 9
// Remember that `Option` is technically a collection of 2 outcomes.
def nameOrNone (maybeName : Option[String]) : Option[String] = {
for (
name <- maybeName
) yield name
}
nameOrNone(maybeKyle)
// Some("kyle")
nameOrNone(maybeHeron)
// None
// You can also do multiple assignments separated by a semicolon. The iteration ends when one assignment ends.
def pairToSum (n : Int, v : Int) : Seq[(Int, Int)] = {
for (
i <- 0 until n;
j <- i until n if (i + j == v)
) yield (i, j)
}
pairToSum(10, 5)
// Seq((0, 5), (1, 4), (2, 3))
// Remember that an `Option` is technically a collection of two outcomes and assignment makes sense.
def pairOrNone (maybeOne : Option[String], maybeTwo : Option[String]) : Option[(Option[String], Option[String])] = {
for (
one <- maybeOne;
two <- maybeTwo
) yield (Some(one), Some(two))
}
pairOrNone(maybeKyle, maybeHeron)
// None
val maybeHeron = Some("heron")
pairOrNone(maybeKyle, maybeHeron)
//Some((Some("kyle"), Some("heron")))
// In the case of using a `Validation` in Gatling, we again have two outcomes: Success, and Failure.
def check(opt : Option[String]) : Validation[String] = {
opt match {
case Some(value) => Success(value)
case None => Failure("undefined value")
}
}
// Now, assignment using a for comprehension makes sense.
val course = for (
id <- check(id)
name <- check(name)
key <- check(key)
) yield Course(id, name, key)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment