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