Scala chain of transformations stopping if error - scala

I want to apply a sequence of transformations to a String but stopping when there is an error. This is an example of a more general pattern (a kind of Chain of Responsibility pattern or Visitor pattern)
If it is possible, I want to avoid using Cats or Scalaz at the moment. If you know how to do it on plain Scala and also Cats/Scalaz I will happy to see the code in the answer ;)
So following is my approach (assertions at the end of the code), but It is not stopping when an error is found. Basically is skipping the execution of the transformation X times.
type Error = String
sealed trait Transformer {
def transform(txt:String) : Either[Error, String]
}
object Transformer1 extends Transformer {
override def transform(txt: String): Either[Error, String] = Right(s"${txt}_One")
}
object Transformer2 extends Transformer {
override def transform(txt: String): Either[Error, String] = Right(s"${txt}_Two")
}
object Transformer3 extends Transformer {
override def transform(txt: String): Either[Error, String] = Right(s"${txt}_Three")
}
object TransformerError extends Transformer {
override def transform(txt: String): Either[Error, String] = Left("Error!!!!")
}
def transform(txt: String, transformers: Seq[Transformer]): Either[Error, String] =
transformers.foldLeft(Right(txt):Either[Error, String])( (result, t) => result match {
case Right(txt) => t.transform(txt)
case error => error
} )
val tOk = Seq(Transformer1, Transformer2, Transformer3)
val tError = Seq(Transformer1, TransformerError, Transformer3)
assert(transform("Whatever", tOk) == Right("Whatever_One_Two_Three"))
assert(transform("Whatever", tError) == Left("Error!!!!"))
Any suggestion?
Thanks!!

In Scala 2.12, Either is right-biased, so for-yield would do the trick.
for {
v1 <- Transformer1.transform("Whatever")
v2 <- Transformer2.transform(v1)
v3 <- Transformer3.transform(v2)
} yield {
v3
}
evaluates to Right(Whatever_One_Two_Three), while
for {
v1 <- Transformer1.transform("Whatever")
v2 <- TransformerError.transform(v1)
v3 <- Transformer3.transform(v2)
} yield {
v3
}
evaluates to Left(Error!!!!)
However, if you would like to return a result with all the transformations applied until an error was reached, that is,
assert(transform("Whatever", tError) == Right("Whatever_One"))
then the following refactoring of transform function might work:
def transform(txt: String, transformers: Seq[Transformer]): Either[Error, String] = {
type Current = Either[Error, String]
type Previous = Either[Error, String]
def foldLeftWithEarlyReturn: Tuple2[Current, Previous] = {
transformers.foldLeft[Tuple2[Current, Previous]](Right(txt) , Right(txt)){
(result, t) => result match {
case ( Right(txt) , Right(previousTxt) ) => ( t.transform(txt) , Right(txt) )
case ( Left(error) , Right(previousTxt) ) => return ( Right(previousTxt), Left(error) )
case e => e
}
}
}
if (foldLeftWithEarlyReturn._1.isLeft)
foldLeftWithEarlyReturn._2 // this means last transformation in sequence resulted in Left, so return previous
else
foldLeftWithEarlyReturn._1
}

When processing a collection, if you want early termination you often have to turn to recursion.
def transform(txt :String
,transformers :Seq[Transformer]
): Either[Error, String] = transformers match {
case Seq() => Right(txt)
case hd +: tl => hd.transform(txt).fold(Left(_), transform(_, tl))
}
A tail-recursive version is also possible, if a little less concise.
#tailrec
def transform(txt :String
,transformers :Seq[Transformer]
): Either[Error, String] = transformers match {
case Seq() => Right(txt)
case hd +: tl =>
val rslt = hd.transform(txt)
if (rslt.isLeft) rslt else transform(rslt.toSeq.head, tl)
}

Pure Scala
Probably, the simplest way to make your code short-circuiting, is to use return statement. It returns the result from the innermost named function it's contained in:
def transform(txt: String, transformers: Seq[Transformer]): Either[Error, String] =
transformers.foldLeft(Right(txt):Either[Error, String])( (result, t) =>
result match {
case Right(txt) => t.transform(txt)
case error => return error
} )
So the return error statement in this code would immediately return the first Left encountered from the transform function.
Cats
In cats you don't really have to do anything special. It short-circuits certain calls for some monads automatically, because monads have to implement tailRecM, and some monads (including Either) implement it in a lazy way to avoid doing useless flatMaps.
import cats.implicits._
def transformCats(txt: String, transformers: List[Transformer]): Either[Error, String] = {
// It seems this is needed to help Scala with type inference.
type Result[T] = Either[Error, T]
// foldLeftM is implemented in terms of tailRecM,
// and thus is short-circuiting for Either
transformers.foldLeftM(txt)((result, tf) => tf.transform(result): Result[String])
}

Related

Scala Function Chaining and handle failure

I have many functions in my code defined with return type as Either[Throwable, String] and all of them have one argument of type String. Three representative functions of my code are defined as:
val f1 = (input: String) => {
/* Processing from the input using a library in my actual code returns a Either[Throwable, String] */
if (input == "a") Left(new Exception(input))
else Right("Success")
}
val f2 = (input: String) => {
if (input == "b") Left(new Exception(input))
else Right("Success")
}
val f3 = (input: String) => {
if (input == "c") Left(new Exception(input))
else Right("Success")
}
To chain the function outputs, I'm writing code like:
def x(input: String) = f1(input) match {
case Left(value) => Left(value)
case Right(_) => f2(input) match {
case Left(value) => Left(value)
case Right(_) => f3(input)
}
}
Since this is just three functions so this might look like a short code. However there are multiple such matches that are happening in my code, so it's a very long code. I am looking to avoid such a chaining.
I know that Scala has a way to chain functions like f1.andThen(f2).andThen(f3), however the problem is that in each andThen we need to pass the same argument, in this case being input. However I want to chain these functions so that if there is a Left output, it should not go to the next andThen.
I believe this can be simplified using Functional Programming, but I don't know where to start. Is there a way we can achieve this using Scala functional programming?
If you have cats in scope, then all you need to do is this:
import cats.syntax.all._
val functions: List[String => Either[Throwable, Unit]] = List(
// put your functions here.
)
val result: Either[Throwable, Unit] =
functions.traverse_(f => f(input))
Otherwise, you may emulate it using this:
val init: Either[Throwable, Unit] = Right(())
functions.foldLeft(init) {
case (acc, f) =>
acc.flatMap(_ => f(input))
}

How do I wrap exception of EitherT into left?

Imagine I have OptionT[IO, Value] like this
case class FailureMsg(code: String, ex: Option[Throwable])
val fff: IO[Either[FailureMsg, Int]] = OptionT.some[IO](12345)
.map { value ⇒
println("Mapping over")
value
}
.flatMapF[Int](_ ⇒ IO.raiseError(new RuntimeException("err1")))
.toRight(FailureMsg("Code0", None))
.recoverWith {
case ex ⇒ // Not Throwable!
EitherT.leftT[IO, Int](FailureMsg("Code1", Some(ex)))
}
.value
How can I catch err1 and wrap it into Left[FailureMsg]. I expected recoverWith help me but surprisingly it's alias of mapLeft. What should I do ?
I wrote helper class to do this.
implicit class EitherTExt[F[_], A, B](val obj: EitherT[F, A, B]) {
def recoverThrowable(pf: PartialFunction[Throwable, Either[A, B]])(implicit A: ApplicativeError[F, Throwable]): EitherT[F, A, B] =
EitherT(obj.value.recover(pf))
}
Let me know if there is more elegant shorter way.
I would follow the types.
val start: OptionT[IO, Int] = OptionT.some[IO](12345)
val thenMap: OptionT[IO, Int] = start.map { value ⇒
println("Mapping over")
value
}
// here it will get off the rails
val thenFlatMapF: OptionT[IO, Int] =
thenMap.flatMapF[Int](_ ⇒ IO.raiseError(new RuntimeException("err1")))
val thenToRight: EitherT[IO, FailureMsg, Int] =
thenFlatMapF.toRight(FailureMsg("Code0", None))
val result: IO[Either[FailureMsg, Int]] = thenToRight.value
thenFlatMapF won't produce OptionT[IO, Int] if IO.raiseError is the case, because no default mapping of Throwable to what? And you will get exception in folding result of IO.raiseError.
First attempt to fix it, will illustrate it:
val thenFlatMapF: OptionT[IO, Int] = thenMap.flatMapF[Int](_ ⇒ {
IO.raiseError[Option[Int]](new RuntimeException("err1")).recoverWith {
case err =>
val result: Option[Int] = ???
IO.pure(result)
}
})
How to handle error in place without breaking IO and return Option so that OptionT[IO, Int] is produced?
So basically, in this case, if you expect flatMapF to fail and need information on error, then it is better to have EitherT as its container, rather than OptionT.
Once done, possible solution shows that at some point leftMap or variance should be done to map the Throwable to FailureMsg. One of reasons is because IO has default error expressed as Throwable. One can't just mix FailureMsg and Throwable. Either inheritance is required so that FailureMsg is of type Throwable/Exception, or mapping should be done of errors in suitable places.
My rough solution would be:
val fff: IO[Either[FailureMsg, Int]] = OptionT.some[IO](12345)
// ok, let's do some input interpretation
.map { value ⇒
println("Mapping over")
value
}
// if no input, means error
.toRight(FailureMsg("Code0", None))
// if there is interpreted input to process, do it and map the errors
.flatMapF(_ ⇒ IO.raiseError[Int](new RuntimeException("err1")).attempt.map(_.leftMap {
case err: RuntimeException if err.getMessage == "err1" => FailureMsg("err1", Some(err))
// just for illustration, that if you have temptation to map on error,
// most likely there won't be only exception
case t: Throwable => FailureMsg("unexpected", Some(t))
}))
.value
However, normally contents of flatMapF would be a separate function or effect that would include error handling. Something like this:
val doJob: Int => IO[Either[FailureMsg, Int]] = arg =>
IO.raiseError[Int](new RuntimeException("err1")).attempt.map(_.leftMap {
case err: RuntimeException if err.getMessage == "err1" => FailureMsg("err1", Some(err))
case t: Throwable => FailureMsg("unexpected", Some(t))
})
val fff: IO[Either[FailureMsg, Int]] = OptionT.some[IO](12345)
.map { value ⇒
println("Mapping over")
value
}
.toRight(FailureMsg("Code0", None))
.flatMapF(arg ⇒ doJob(arg))
.value

How to express Function type?

I am currently reading Hutton's and Meijer's paper on parsing combinators in Haskell http://www.cs.nott.ac.uk/~pszgmh/monparsing.pdf. For the sake of it I am trying to implement them in scala. I would like to construct something easy to code, extend and also simple and elegant. I have come up with two solutions for the following haskell code
/* Haskell Code */
type Parser a = String -> [(a,String)]
result :: a -> Parser a
result v = \inp -> [(v,inp)]
zero :: Parser a
zero = \inp -> []
item :: Parser Char
item = \inp -> case inp of
[] -> []
(x:xs) -> [(x,xs)]
/* Scala Code */
object Hutton1 {
type Parser[A] = String => List[(A, String)]
def Result[A](v: A): Parser[A] = str => List((v, str))
def Zero[A]: Parser[A] = str => List()
def Character: Parser[Char] = str => if (str.isEmpty) List() else List((str.head, str.tail))
}
object Hutton2 {
trait Parser[A] extends (String => List[(A, String)])
case class Result[A](v: A) extends Parser[A] {
def apply(str: String) = List((v, str))
}
case object Zero extends Parser[T forSome {type T}] {
def apply(str: String) = List()
}
case object Character extends Parser[Char] {
def apply(str: String) = if (str.isEmpty) List() else List((str.head, str.tail))
}
}
object Hutton extends App {
object T1 {
import Hutton1._
def run = {
val r: List[(Int, String)] = Zero("test") ++ Result(5)("test")
println(r.map(x => x._1 + 1) == List(6))
println(Character("abc") == List(('a', "bc")))
}
}
object T2 {
import Hutton2._
def run = {
val r: List[(Int, String)] = Zero("test") ++ Result(5)("test")
println(r.map(x => x._1 + 1) == List(6))
println(Character("abc") == List(('a', "bc")))
}
}
T1.run
T2.run
}
Question 1
In Haskell, zero is a function value that can be used as it is, expessing all failed parsers whether they are of type Parser[Int] or Parser[String]. In scala we achieve the same by calling the function Zero (1st approach) but in this way I believe that I just generate a different function everytime Zero is called. Is this statement true? Is there a way to mitigate this?
Question 2
In the second approach, the Zero case object is extending Parser with the usage of existential types Parser[T forSome {type T}] . If I replace the type with Parser[_] I get the compile error
Error:(19, 28) class type required but Hutton2.Parser[_] found
case object Zero extends Parser[_] {
^
I thought these two expressions where equivalent. Is this the case?
Question 3
Which approach out of the two do you think that will yield better results in expressing the combinators in terms of elegance and simplicity?
I use scala 2.11.8
Note: I didn't compile it, but I know the problem and can propose two solutions.
The more Haskellish way would be to not use subtyping, but to define zero as a polymorphic value. In that style, I would propose to define parsers not as objects deriving from a function type, but as values of one case class:
final case class Parser[T](run: String => List[(T, String)])
def zero[T]: Parser[T] = Parser(...)
As shown by #Alec, yes, this will produce a new value every time, since a def is compiled to a method.
If you want to use subtyping, you need to make Parser covariant. Then you can give zero a bottom result type:
trait Parser[+A] extends (String => List[(A, String)])
case object Zero extends Parser[Nothing] {...}
These are in some way quite related; in system F_<:, which is the base of what Scala uses, the types _|_ (aka Nothing) and \/T <: Any. T behave the same (this hinted at in Types and Programming Languages, chapter 28). The two possibilities given here are a consequence of this fact.
With existentials I'm not so familiar with, but I think that while unbounded T forSome {type T} will behave like Nothing, Scala does not allow inhertance from an existential type.
Question 1
I think that you are right, and here is why: Zero1 below prints hello every time you use it. The solution, Zero2, involves using a val instead.
def Zero1[A]: Parser[A] = { println("hi"); str => List() }
val Zero2: Parser[Nothing] = str => List()
Question 2
No idea. I'm still just starting out with Scala. Hope someone answers this.
Question 3
The trait one will play better with Scala's for (since you can define custom flatMap and map), which turns out to be (somewhat) like Haskell's do. The following is all you need.
trait Parser[A] extends (String => List[(A, String)]) {
def flatMap[B](f: A => Parser[B]): Parser[B] = {
val p1 = this
new Parser[B] {
def apply(s1: String) = for {
(a,s2) <- p1(s1)
p2 = f(a)
(b,s3) <- p2(s2)
} yield (b,s3)
}
}
def map[B](f: A => B): Parser[B] = {
val p = this
new Parser[B] {
def apply(s1: String) = for ((a,s2) <- p(s1)) yield (f(a),s2)
}
}
}
Of course, to do anything interesting you need more parsers. I'll propose to you one simple parser combinator: Choice(p1: Parser[A], p2: Parser[A]): Parser[A] which tries both parsers. (And rewrite your existing parsers more to my style).
def choice[A](p1: Parser[A], p2: Parser[A]): Parser[A] = new Parser[A] {
def apply(s: String): List[(A,String)] = { p1(s) ++ p2(s) }
}
def unit[A](x: A): Parser[A] = new Parser[A] {
def apply(s: String): List[(A,String)] = List((x,s))
}
val character: Parser[Char] = new Parser[Char] {
def apply(s: String): List[(Char,String)] = List((s.head,s.tail))
}
Then, you can write something like the following:
val parser: Parser[(Char,Char)] = for {
x <- choice(unit('x'),char)
y <- char
} yield (x,y)
And calling parser("xyz") gives you List((('x','x'),"yz"), (('x','y'),"z")).

Scala Pattern Matching pretty printed

Is that possible to somehow marshall PartialFunction (let's assume it will always contains only one case) into something human-readable?
Let's say we have collection of type Any (messages: List[Any])
and number of PartialFuntion[Any, T] defined using pattern matching block.
case object R1
case object R2
case object R3
val pm1: PartialFunction[Any, Any] = {
case "foo" => R1
}
val pm2: PartialFunction[Any, Any] = {
case x: Int if x > 10 => R2
}
val pm3: PartialFunction[Any, Any] = {
case x: Boolean => R3
}
val messages: List[Any] = List("foo", 20)
val functions = List(pm1, pm2)
then we can find all the messages matched by provided PFs and related applications
val found: List[Option[Any]] = functions map { f =>
messages.find(f.isDefined).map(f)
}
but what if I need resulting map of 'what I expect' to 'what I've got' in the human-readable form (for logging). Say,
(case "foo") -> Some(R1)
(case Int if _ > 10) -> Some(R2)
(case Boolean) -> None
Is that possible? Some macro/meta works?
There's nothing at runtime which will print compiled code nicely.
You could write a macro which will print the source code of the tree and use that? Most macro tutorials start with a macro for printing source code -- see e.g. http://www.warski.org/blog/2012/12/starting-with-scala-macros-a-short-tutorial/
Perhaps:
// Given a partial function "pf", return the source code for pf
// as a string as well as the compiled, runnable function itself
def functionAndSource(pf: PartialFunction[Any, Any]): (String, PartialFunction[Any, Any]) = macro functionAndSourceImpl
def functionAndSourceImpl ...
val pm1: (String, PartialFunction[Any, Any]) = functionAndSource {
case "foo" => R1
}
This isn't ever going to be that easy or nice in Scala.
Scala isn't Lisp or Ruby: it's a compiled language and it is not optimised for reflection on the code itself.
Thanks for your answers. Using Macro is interesting one choice.
But as an option the solution might be to use kind of named partial functions. The idea is to name the function so in the output you can see the name of function instead source code.
object PartialFunctions {
type FN[Result] = PartialFunction[Any, Result]
case class NamedPartialFunction[A,B](name: String)(pf: PartialFunction[A, B]) extends PartialFunction[A,B] {
override def isDefinedAt(x: A): Boolean = pf.isDefinedAt(x)
override def apply(x: A): B = pf.apply(x)
override def toString(): String = s"matching($name)"
}
implicit class Named(val name: String) extends AnyVal {
def %[A,B](pf: PartialFunction[A,B]) = new NamedPartialFunction[A, B](name)(pf)
}
}
So then you can use it as follows
import PartialFunctions._
val pm1: PartialFunction[Any, Any] = "\"foo\"" % {
case "foo" => R1
}
val pm2: PartialFunction[Any, Any] = "_: Int > 10" % {
case x: Int if x > 10 => R2
}
val pm3: PartialFunction[Any, Any] = "_: Boolean" % {
case x: Boolean => R3
}
val messages: List[Any] = List("foo", 20)
val functions = List(pm1, pm2)
val found: List[Option[(String, Any)]] = functions map { case f: NamedPartialFunction =>
messages.find(f.isDefined).map(m => (f.name, f(m))
}

Scala - reduce/foldLeft

I have a nested map m which is like:
m = Map("email" -> "a#b.com", "background" -> Map("language" -> "english"))
I have an array arr = Array("background","language")
How do I foldLeft/reduce the array and find the string "english" from the map. I tried this:
arr.foldLeft(m) { (acc,x) => acc.get(x) }
But I get this error:
<console>:10: error: type mismatch;
found : Option[java.lang.Object]
required: scala.collection.immutable.Map[java.lang.String,java.lang.Object]
arr.foldLeft(m) { (acc,x) => acc.get(x) }
You should pay attention to types. Here, you start with m : Map[String, Any] as your acc. You combine with a string x and calls get, which returns an Option[Object]. To continue, you must check that there is a value, check whether this value is a Map, cast (unchecked because of type erasure, hence dangerous).
I believe the fault is in the that the type of your structure, Map[String, Any] represents what you have rather poorly.
Suppose you do instead
sealed trait Tree
case class Node(items: Map[String, Tree]) extends Tree
case class Leaf(s: String) extends Tree
You may add some helpers to make declaring a Tree easy
object Tree {
implicit def fromString(s: String) = Leaf(s)
implicit def fromNamedString(nameAndValue: (String, String))
= (nameAndValue._1, Leaf(nameAndValue._2))
}
object Node {
def apply(items: (String, Tree)*) : Node = Node(Map(items: _*))
}
Then declaring the tree is just as easy as your first version, but the type is much more precise
m = Node("email" -> "a#b.com", "background" -> Node("language" -> "english"))
You can then add methods, for instance in trait Tree
def get(path: String*) : Option[Tree] = {
if (path.isEmpty) Some(this)
else this match {
case Leaf(_) => None
case Node(map) => map.get(path.head).flatMap(_.get(path.tail: _*))
}
}
def getLeaf(path: String*): Option[String]
= get(path: _*).collect{case Leaf(s) =>s}
Or if you would rather do it with a fold
def get(path: String*) = path.foldLeft[Option[Tree]](Some(this)) {
case (Some(Node(map)), p) => map.get(p)
case _ => None
}
Folding as an abstraction over nested maps isn't really supported. Also, you're approaching this in a way that is going to prevent the type system from giving you much help. But, if you insist, then you want a recursive function:
def lookup(m: Map[String,Object], a: Array[String]): Option[String] = {
if (a.length == 0) None
else m.get(a(0)).flatMap(_ match {
case mm: Map[_,_] => lookup(mm.asInstanceOf[Map[String,Object]],a.tail)
case s: String if (a.length==1) => Some(s)
case _ => None
})
}