Created
September 11, 2013 22:42
-
-
Save aappddeevv/6530787 to your computer and use it in GitHub Desktop.
scala monoids and for comprehensions examples
This file contains 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
// Define functions that return an Option | |
def f1(x: Int): Option[Int] = Some(x*30) | |
def f2(x: Int): Option[Int] = Some(x+3) | |
def f3(x: Int): Option[Int] = Some(x*2) | |
// Sequence the computation, it will be successful | |
var answer = for { | |
x <- f1(30) | |
y <- f2(x) | |
z <- f3(y) | |
} yield (x,y,z) | |
println("answer: " + answer) | |
// Sequence the computation, the filter will be used | |
answer = for { | |
x <- f1(30) | |
y <- f2(x) if(x>1000) | |
z <- f3(y) | |
} yield (x,y,z) | |
println("answer with filter: " + answer) | |
// Define functions that return Either | |
// Note that e2b returns Left as if it is an error. | |
def e1(x: Int): Either[String, Int] = Right(x*30) | |
def e2(x: Int): Either[String, Int] = Right(x+3) | |
def e2b(x: Int): Either[String, Int] = Left("error") | |
def e3(x: Int): Either[String, Int] = Right(x*2) | |
// Sequence the computations, knowing it will succeed | |
var eanswer = for { | |
x <- e1(30).right | |
y <- e2(x).right | |
z <- e3(y).right | |
} yield z | |
println("eanswer: " + eanswer) | |
// Sequence computations, knowing that it will have an error | |
eanswer = for { | |
x <- e1(30).right | |
y <- e2b(x).right | |
z <- e3(y).right | |
} yield z | |
println("eanswer (with Left()): " + eanswer) | |
/** Prints: | |
answer: Some((900,903,1806)) | |
answer with filter: None | |
eanswer: Right(1806) | |
eanswer (with Left()): Left(error) | |
**/ | |
// The following does not compile | |
// eanswer = for { ... y <- e2b(x).left ... } ... | |
// Because e3, the function after e2b is called expects an int, | |
// but Left contains a String so when it is unwrapped to call | |
// e3 it is the wrong type. Scala compile time checks catch this! | |
// Either, Left and Right do not have a withFilter method | |
// so you cannot use if() clauses in for comprehensions directly | |
// when using Either. Option has a withFilter method. | |
println("Filter on <200: " + e2(33).right.filter[String](_<200)) | |
println("Filter on >200: " + e2(33).right.filter[String](_ > 200)) | |
/** Prints: | |
Filter on <200: Some(Right(36)) | |
Filter on >200: None | |
**/ | |
// Sequencing using just the Either monad and no filter | |
// criteria used on any of the map lines. | |
// Generally, when using a filter, check the scala | |
// docs for the monoid you are using (e.g. Option or | |
// Either) to understand what map, flatMap and withFilter | |
// do when applied to the monoid value. If withFilter | |
// is not present, then you may have difficulty using | |
// an if-condition on one of the "map" lines. | |
// | |
// Note that it does not make sense to have a withFilter | |
// on an Either. When using withFilter on an Option monoid, | |
// if the filter selects false (and hence returns a None), | |
// then a Some(yourValue) becomes a None. Both of which are | |
// well defined. But if you use either and the Right(yourValue) | |
// (or left depending on which 1/2 you use) is not selected, | |
// you need to return Left(someOtherYourValue) but someOtherYourValue | |
// is never defined automatically so there is no "automatic" | |
// other value to use. That's why you cannot apply a filter | |
// using the for-comprehension syntax. | |
// | |
// In the for-comprehension below, if a Left appears as a result | |
// of the function call, the for terminates immediately and returns | |
// the Left as the value. | |
var eanswer2 = for { | |
x <- e1(30).right | |
y <- e2(x).right | |
z <- e3(y).right | |
} yield z | |
println("eanswer with no filter: " + eanswer2) | |
/** Prints: | |
eanswer with no filter: Right(1806) | |
**/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment