Last active
September 22, 2017 23:55
-
-
Save kwiest/986bfe832718726f7ccba6d86e915dd1 to your computer and use it in GitHub Desktop.
Understanding flatMap and for comprehentions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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