Created
January 5, 2017 10:09
-
-
Save jonnylaw/99460d466c84d9b52b57010d28b6a4f6 to your computer and use it in GitHub Desktop.
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
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