import scala.util.{Try, Success, Failure} def f(s: String): Try[Int] = Try { s.toInt } def g(i: Int): Try[Int] = Try { i * 2 } def unit[T](v: T): Try[T] = Success(v) //val v = "1" val v = "bad" val m = Success(v) // Monad Laws. At first glance, does `Try` pass laws if `v` == "bad"? No. assert(f(v) == unit(v).flatMap(f)) assert(m == m.flatMap(unit)) assert(m.flatMap(f).flatMap(g) == m.flatMap(n => f(n).flatMap(g))) // (a) Does `Try` pass laws if `f` throws a constant exception? Yes. val ce = new RuntimeException("always the same exception instance") def f(s: String): Try[Int] = Try { throw ce } // (b) Does `Try` pass laws if `f` wraps an uncaught exception in Success? No. def f(s: String): Try[Int] = if (false) Failure(ce) else Success(throw ce) // (c) Does `Try` pass laws if `f` wraps an uncaught exception in Try? Yes. def f(s: String): Try[Int] = if (false) Failure(ce) else Try(throw ce)