Skip to content

Instantly share code, notes, and snippets.

@igstan
Last active August 29, 2015 14:14
Show Gist options
  • Save igstan/46607bf12c8922a11bca to your computer and use it in GitHub Desktop.
Save igstan/46607bf12c8922a11bca to your computer and use it in GitHub Desktop.
/*
* Assume you have a bunch of methods that return `Option` and you want to
* produce very precise output about which of those methods returned a `None`
* in case of "failure".
*
* There are a few strategies to doing that. Here are three of them:
*/
object Main {
def foo: Option[String] = Some("foo")
def bar(x: String): Option[String] = None
def baz(y: String): Option[String] = Some(y)
def main(args: Array[String]): Unit = {
println(usingPatternMatching)
println(usingStandardOptionCombinators)
println(usingScalaz)
}
/*
* Using standard pattern matching on `Option`:
*/
def usingPatternMatching: String = {
foo match {
case None => "missing foo"
case Some(a) =>
if (a != "foo") {
"value not conforming"
} else {
bar(a) match {
case None => "missing bar"
case Some(b) =>
baz(b) match {
case None => "missing baz"
case Some(c) => c
}
}
}
}
}
/*
* Using predefined combinators on `Option`:
*/
def usingStandardOptionCombinators: String = {
foo.map { a =>
if (a == "foo") {
bar(a).map { b =>
baz(b) getOrElse "missing baz"
} getOrElse "missing bar"
} else "value not conforming"
} getOrElse "missing foo"
}
/*
* Using Scalaz extensions:
*/
def usingScalaz: String = {
import scalaz.syntax.std.option._
import scalaz.syntax.std.boolean._
val r = for {
a <- foo \/> "missing foo"
b <- (a == "foo").option(a) \/> "value not conforming"
c <- bar(b) \/> "missing bar"
d <- baz(c) \/> "missing baz"
} yield d
r.merge
}
}
@OleTraveler
Copy link

I'd suggest returning String/String from your methods where the Left or -/ side is the failure.

If you want all errors instead of the just the first missing one, use Validation and the applicative builder instead of a for comprehension.

@igstan
Copy link
Author

igstan commented Jan 26, 2015

@OleTraveler thanks! I really need to merge the two cases of \/. This was a contrived example, but I need the actual code to return an HTTP response, which would be 4XX for Left and 2XX for Right.

Also, I do indeed need the first missing one, because there's a data dependency between all the methods that return Option, which is why I didn't use Validation.

@OleTraveler
Copy link

Sorry, I didn't RTFM at the top. What you have looks good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment