### Making a safe RPN calculator

LYAHFGG:

When we were solving the problem of implementing a RPN calculator, we noted that it worked fine as long as the input that it got made sense.

We have not covered the chapter on RPN calculator, so let’s translate it into Scala.

``````scala> def foldingFunction(list: List[Double], next: String): List[Double] =
(list, next) match {
case (x :: y :: ys, "*") => (y * x) :: ys
case (x :: y :: ys, "+") => (y + x) :: ys
case (x :: y :: ys, "-") => (y - x) :: ys
case (xs, numString) => numString.toInt :: xs
}
foldingFunction: (list: List[Double], next: String)List[Double]
scala> def solveRPN(s: String): Double =
(s.split(' ').toList.
solveRPN: (s: String)Double
scala> solveRPN("10 4 3 + 2 * -")
res0: Double = -4.0``````

Looks like it’s working.

The next step is to change the folding function to handle errors gracefully. We can implement `parseInt` as follows:

``````scala> import scala.util.Try
import scala.util.Try
scala> def parseInt(x: String): Option[Int] =
(scala.util.Try(x.toInt) map { Some(_) }
recover { case _: NumberFormatException => None }).get
parseInt: (x: String)Option[Int]
scala> parseInt("1")
res1: Option[Int] = Some(1)
scala> parseInt("foo")
res2: Option[Int] = None``````

Here’s the updated folding function:

``````scala> import cats._, cats.data._, cats.implicits._
import cats._
import cats.data._
import cats.implicits._
scala> def foldingFunction(list: List[Double], next: String): Option[List[Double]] =
(list, next) match {
case (x :: y :: ys, "*") => ((y * x) :: ys).some
case (x :: y :: ys, "+") => ((y + x) :: ys).some
case (x :: y :: ys, "-") => ((y - x) :: ys).some
case (xs, numString) => parseInt(numString) map {_ :: xs}
}
foldingFunction: (list: List[Double], next: String)Option[List[Double]]
scala> foldingFunction(List(3, 2), "*")
res3: Option[List[Double]] = Some(List(6.0))
scala> foldingFunction(Nil, "*")
res4: Option[List[Double]] = None
scala> foldingFunction(Nil, "wawa")
res5: Option[List[Double]] = None``````

Finally, here’s the updated `solveRPN` using `foldM`:

``````scala> def solveRPN(s: String): Option[Double] =
for {
List(x) <- (Foldable[List].foldM(s.split(' ').toList, Nil: List[Double]) {foldingFunction})
} yield x
solveRPN: (s: String)Option[Double]
scala> solveRPN("1 2 * 4 +")
res6: Option[Double] = Some(6.0)
scala> solveRPN("1 2 * 4")
res7: Option[Double] = None
scala> solveRPN("1 8 garbage")
res8: Option[Double] = None``````