More idiomatic (monadic?) way to express this Scala

monads, scala

Solution

These types of problems are just what `Try` aims to solve a bit more monadically (than nested `try/catch` blocks).

`Try` represents a computation that may either result in an exception, or return a successfully computed value. It has two subclasses for these-- `Success` and `Failure`.

Very funny that this question popped up when it did-- a few days ago, I finished up some additions and refactoring to `scala.util.Try`, for the 2.10 release and this SO question helps to illustrate an important use-case for a combinator that we eventually decided to include; `transform`.

(As of writing this, `transform` is currently in the nightly and will be in Scala from 2.10-M5 onward, due out today or tomorrow. More info about `Try` and usage examples can be found in the nightly docs)

With `transform` (by nesting them), this can be implemented using `Try`s as follows:

def test(s: String): Double = {
  Try(fA(s)).transform(
    ea => Success(result(0, 0.0, false)), a => Try(fB(s, a)).transform(
      eb => Success(result(a, 0.0, false)), b => Try(fC(s, a, b)).transform(
        ec => Success(result(a, b, false)), c => Try(result(a, b, c))
      )
    )
  ).get
}

Problem

I have several blocks of code that follow this pattern: ``` // Dummy function defs. def result(i : Int, d : Double, b : Boolean) = { if (b) d else i } def fA(s : String) = {7} def fB(s : String, i : Int) = {1.0} def fC(s : String, i : Int, d : Double) = {true} // Actual code. def test(s : String) : Double = { try { val a = fA(s) try { val b = fB(s, a) try { val c = fC(s, a, b) result(a, b, c) } catch { case _ => result(a, b, false) } } catch { case _ => result(a, 0.0, false) } } catch { case _ => result(0, 0.0, false) } } ``` Where a, b, & c are calculated in turn by the corresponding functions and then the values are passed to the result function. If at any stage an exception occurs then a default value is used in place of the remaining variables. Is there a more idiomatic way to express this code. It reminds me of Monads in that it's a series of chained computations which bail out immediately if any computation fails.

Original source