Skip to content

Instantly share code, notes, and snippets.

@jonnylaw
Created January 5, 2017 10:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonnylaw/99460d466c84d9b52b57010d28b6a4f6 to your computer and use it in GitHub Desktop.
Save jonnylaw/99460d466c84d9b52b57010d28b6a4f6 to your computer and use it in GitHub Desktop.
import cats.implicits._
import cats.data.OptionT
object ErrorHandling {
// Calculate the square root of a positive number or return an exception (which isn't obvious from the return type)
def unsafe_sqrt(a: Double): Double = {
if (a > 0) math.sqrt(a)
else throw new Exception("Can't calculate square root of negative number")
}
// Calculate the square root of a positive number and return either a Success containing the result
// or a Failure containing an exception (if the number supplied is negative)
// This makes it clear to users that this function can fail
def try_sqrt(a: Double): Try[Double] = {
if (a > 0) Success(math.sqrt(a))
else Failure(throw new Exception("Can't calculate square root of negative number"))
}
// Calculate the square root of a positive number and return an optional value
def option_sqrt(a: Double): Option[Double] = {
if (a > 0) Some(math.sqrt(a))
else None
}
// In order to chain operations we can use compose on the function unsafe_sqrt
// this is because the function has compatible types (Double => Double)
def sqrt_twice = unsafe_sqrt _ compose unsafe_sqrt _
// In order to chain the option_sqrt function, we need to invoke flatMap, since the
// types are not compatible
def sqrt_twice_option(x: Double): Option[Double] =
option_sqrt(x) flatMap option_sqrt
// A naive attempt to compose a try and an option using nested type constructors
// This appears to work, but becomes more difficult if we want to work with the return type
def sqrt_twice_2(a: Double): Try[Option[Double]] = try_sqrt(a) map option_sqrt
// Another function we want to apply to the result of sqrt_twice_2
def f(a: Double) = a + 1
// Function which applies f to the result of sqrt_twice_2
def apply_f = sqrt_twice_2(81) map (_.map(f))
// We can remove the extra map function by utilising OptionT from cats (http://typelevel.org/cats/),
// a monad transformer for Option
def sqrt_twice_trans(a: Double): OptionT[Try, Double] =
OptionT.fromOption[Try](option_sqrt(a)) flatMap (b => OptionT.liftF(try_sqrt(b))
def apply_f_trans = sqrt_twice_trans(81) map f
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment