Scala: better nested multiple condition check - scala

Lately, I frequently end up writing code like that:
def doSomethingWithLotsOfConditions(arg1, arg2, arg3...) {
arg1.get(arg2) match {
case Some(value1) =>
arg3.get(value1) match {
case Some(value2) =>
arg4.get(arg5, value2) match {
case Some(value3) =>
finallyDoSomethingInside(value3)
case None =>
log("Some excuse for being unable to work with arg4/arg5...")
}
case None =>
log("Some excuse for being unable to work with arg3")
}
case None =>
log("Some excuse for being unable to work with arg1/arg2")
}
}
A somewhat related question seems to heavily advocate for such usage of nested match, although, from my point of view, it hardly seems readable, concise or easy-to-understand: (1) it kind of splits the check itself and its aftermath, (2) it makes code uncontrollably nested without any real rationale for nesting. In these particular cases, I would be glad to structure the code something in lines of:
def doSomethingWithLotsOfConditions(arg1, arg2, arg3...) {
// Step 1
val value1Opt = arg1.get(arg2)
if (value1Opt.isEmpty) {
log("Some excuse for being unable to work with arg1/arg2")
return
}
val value1 = value1Opt.get
// Step 2
val value2Opt = arg3.get(value1)
if (value2Opt.isEmpty) {
log("Some excuse for being unable to work with arg3")
return
}
val value2 = value2Opt.get
// Step 3
val value3Opt = arg4.get(arg5, value2)
if (value3Opt.isEmpty) {
log("Some excuse for being unable to work with arg4/arg5...")
return
}
val value3 = value3Opt.get
// All checked - we're free to act!
finallyDoSomethingInside(value3)
}
However, that pattern (i.e. valueXOpt = (...).get => check isEmpty => value = valueXOpt.get) looks really ugly and is also definitely too verbose. Hell, even Java version would look more concise:
Value1Type value1 = arg1.get(arg2);
if (value1 != null) {
log("Some excuse for being unable to work with arg1/arg2");
return;
}
Is there a better, cleaner alternative, i.e. for getting the value and specifying alternative short escape route (that log a line + return), without going nested with matches?

How about this?
object Options{
implicit class OptionLog[T](val option:Option[T]) extends AnyVal{
def ifNone(body: =>Unit):Option[T] = option.orElse {
body
option
}
}
}
import Options._
def something(arg1:Option[Int], arg2:Option[String], arg3:Option[Long], arg4:Option[Any]){
for{
val1 <- arg1 ifNone(println("arg1 was none"))
val2 <- arg2 ifNone(println("arg2 was none"))
val3 <- arg3 ifNone(println("arg3 was none"))
}{
println(s"doing something with $val1, $val2, $val3")
}
}
Then ...
scala> something(Some(3), Some("hello"), None, Some("blah"))
arg3 was none
scala> something(Some(3), Some("hello"), Some(10l), Some("blah"))
doing something with 3, hello, 10

Maybe you mean, for a condition x:
scala> def f(x: Option[Int]): Int = x orElse { println("nope"); return -1 } map (_ + 1) getOrElse -2
f: (x: Option[Int])Int
scala> f(Some(5))
res3: Int = 6
scala> f(None)
nope
res4: Int = -1
or even
scala> def f(x: Option[Int], y: Option[Int]): Int = (for (i <- x orElse { println("nope"); return -1 }; j <- y orElse { println("gah!"); return -2 }) yield i + j) getOrElse -3
f: (x: Option[Int], y: Option[Int])Int
scala> f(Some(5), None)
gah!
res5: Int = -2
Sorry if I'm oversimplifying.

Don't you want to use the map method?
def doSomethingWithLotsOfConditions(arg1, arg2, arg3...) =
arg1.get(arg2).map(value1 =>
arg3.get(value1).map(value2 =>
arg4.get(arg5, value2).map(value3 =>
finallyDoSomethingInside(value3)).
getOrElse(log("Some excuse for being unable to work with arg4/arg5"))).
getOrElse(log("Some excuse for being unable to work with arg3"))).
getOrElse(log("Some excuse for being unable to work with arg1/arg2"))
It is still nested but it's at least more elegant-looking than your pattern matching above.
Or you can implement your own Functor for this one:
trait Foo[+A] {
def fmap[B](f: A => B): Foo[B]
}
case class Bar[A](value: A) {
def fmap[B](f: A => B): Foo[B] = Bar(f(value))
}
case object Error[Nothing](message: String) {
def fmap[B](f: Nothing => B) = Error(message)
}
def doSomethingWithLotsOfConditions(arg1, arg2, arg3, arg4, arg5) =
arg1.get(arg2).fmap(value1 =>
arg3.get(value1).fmap(value2 =>
arg4.get(arg5, value2).fmap(value3 =>
finallyDoSomethingInside))
def processResult = doSomethingWithLotsOfConditions(...) match {
case Bar(a) => doSomething
case Error(message) => log(message)
}
This code assumes that arg.get returns a Foo.

Related

How do I call a method that only exists on one of the 2 types in an Either?

I have an array of objects of type Either[A, B]. If I know for a particular element whether it is an A or a B, how do I call a method on it that only exists on one of the 2 types. For example:
import scala.util.Random
object EitherTest extends App {
def newObj(x: Int): Either[A,B] = {
if (x == 0)
Left(new A())
else
Right(new B())
}
val random = new Random()
val randomArray = (0 until 10).map(_ => random.nextInt(2))
val eitherArray = randomArray.map(newObj)
(0 until 10).foreach(x => randomArray(x) match {
case 0 => eitherArray(x).aMethod()
case 1 => eitherArray(x).bMethod()
case _ => println("Error!")
})
}
class A {
def aMethod() = println("A")
}
class B {
def bMethod() = println("B")
}
When I compile this code, the lines
case 0 => eitherArray(x).aMethod()
case 1 => eitherArray(x).bMethod()
both have the error "value aMethod is not a member of Either[A,B]". How can I solve this?
I don't know why fold doesn't get the respect it deserves. It can be so useful.
eitherArray.foreach(_.fold(_.aMethod(), _.bMethod()))
Well, you can do it if you exctract the logic to another method, and do some pattern matching over the value Either, then check if it is Right or Left, and that's it!
object HelloWorld {
import scala.util.Random
def main(args: Array[String]) {
val random = new Random()
val randomArray = (0 until 10).map(_ => random.nextInt(2))
val eitherArray = randomArray.map(EitherTest.newObj)
(0 until 10).foreach(x => randomArray(x) match {
case 0 => EitherTest.callmethod(eitherArray(x))
case 1 => EitherTest.callmethod(eitherArray(x))
case _ => println("Error!")
})
println("Hello, world!")
}
}
class EitherTest
object EitherTest {
def callmethod(ei : Either[A,B]) = {
ei match {
case Left(a) => a.aMethod()
case Right(b) => b.bMethod()
}
}
def newObj(x: Int): Either[A,B] = {
if (x == 0)
Left(new A())
else
Right(new B())
}
}
class A {
def aMethod() = println("A")
}
class B {
def bMethod() = println("B")
}
Will print for you, for one random example:
A
B
A
B
A
A
A
B
B
B
Hello, world!
Basically, the way you do with Either is projections: Either.left gives you the projection of the left type, and Either.right gives you that of the right.
The projections are somewhat similar to options, in that they can be empty (if your Either is a Right, then the left projection is empty and vice versa), and you can use the usual monadic transformations with them, like map, flatMap, foreach, getOrElse etc.
Your example, could look like this:
randomArray.foreach { either =>
either.left.foreach(_.aMethod)
either.right.foreach(_.bMethod)
}
You could also use pattern-matching instead, that's less general, but, perhaps looks a bit clearer in this case:
randomArray.foreach {
case Left(a) => a.aMethod
case Right(b) => b.bMethod
}

Scala: expanded syntax of trampolining function breaks tail recursion

This is an exercise in "Functional Programming in Scala," chapter 13, to implement a trampoline for interpreting tail-recursive functions.
runTrampoline2 is not tail-recursive, and overflows the stack with my test inputs. Furthermore, the tailrec annotation gives a compiler error for runTrampoline2. runTrampoline is tail-recursive and passes the annotation's compile-time check.
My best bet is that the difference between these two trampolines lies in the way a val captures, or doesn't capture, a Unit, like here:
scala> val foo = println("abc")
val foo = println("abc")
abc
foo: Unit = ()
scala> foo
foo
scala> val bar: Int = {println("xyz"); 5}
val bar: Int = {println("xyz"); 5}
xyz
bar: Int = 5
scala> bar
bar
res8: Int = 5
Otherwise these two trampolines look identical to me. I'll include the code for the Free monad and the Suspend, Return, and FlatMap constructors if someone comments they are important for this question, but I don't think they are. Is runTrampoline2's tail-recursion broken by a side effect leaking out of the vals? Thanks!
#annotation.tailrec
def runTrampoline[A](tra: Free[Function0,A]): A =
tra match {
// case Return(A)
case Return(a1) => a1
// case Suspend(Function0[A])
case Suspend(function0A1) => function0A1()
// case FlatMap(Free[Function0[_],A], A=>Free[Function0,B]]
case FlatMap(free1, aFree2) => free1 match {
// case Return(A)
case Return(a2) => runTrampoline(aFree2(a2))
// case Suspend(Function0[A])
case Suspend(function0A) => runTrampoline(aFree2(function0A()))
// case FlatMap(Free[Function0[_],A], A=>Free[Function0,B]]
case FlatMap(a0,g) =>
runTrampoline {
a0 flatMap { a0 => g(a0) flatMap aFree2 }
}
}
}
//#annotation.tailrec
def runTrampoline2[A](tra: Free[Function0,A]): A =
tra match {
// case Return(A)
case Return(a1) => a1
// case Suspend(Function0[A])
case Suspend(function0A1) => {
val a1: A = function0A1()
a1
}
// case FlatMap(Free[Function0[_],A], A=>Free[Function0,A]]
case FlatMap(free1, aFree2) => free1 match {
// case Return(A)
case Return(a2) => {
val free2: Free[Function0,A] = aFree2(a2)
val a3: A = runTrampoline2(free2)
a3
}
// case Suspend(Function0[A])
case Suspend(function0A) => {
val a2: A = function0A()
val free2: Free[Function0,A] = aFree2(a2)
val a3: A = runTrampoline2(free2)
a3
}
// case FlatMap(Free[Function0[_],A], A=>Free[Function0,B]]
case FlatMap(a0,g) =>
runTrampoline2 {
a0 flatMap { a0 => g(a0) flatMap aFree2 }
}
}
}
I asked a similar question a month ago, about type annotations breaking tail-recursion: Scala: type annotations make tail recursion check fail
Solved by Aivean. Here is a corrected version of the trampoline. Each recursive call is at the very end of the case containing it.
#annotation.tailrec
def runTrampoline3[A](tra: Free[Function0,A]): A =
tra match {
case Return(a1) => a1
case Suspend(function0A1) => {
val a1 = function0A1()
a1
}
case FlatMap(free1, aFree2) => free1 match {
case Return(a2) => {
val free2 = aFree2(a2)
runTrampoline3(free2)
}
case Suspend(function0A) => {
val a2 = function0A()
val free2 = aFree2(a2)
runTrampoline3(free2)
}
case FlatMap(a0,g) =>
runTrampoline3 {
a0 flatMap { a0 => g(a0) flatMap aFree2 }
}
}
}
It appears that Scala compiler recognizes tail recursion only when call to itself is actually the last operation in the function.
I decompiled two different examples to check this.
Tail recursion:
scala:
def rec:Int = rec
java:
public final class _$$anon$1 {
private int rec() {
while (true) {}
}
}
No tail recursion:
scala:
def rec:Int = {
val i = rec
i
}
java:
public final class _$$anon$1 {
private int rec() {
final int i = this.rec();
return i;
}
}

Converting multiple optional values in Scala

I am writing a function that receives several optional String values and converts each one to either an Int or a Boolean and then passes the converted values to Unit functions for further processing. If any conversion fails, the entire function should fail with an error. If all conversions succeed, the function should process the converted values and return a success.
Here is the function I have written (simplified from the actual):
f(x: Option[String], y: Option[String], z: Option[String]): Result = {
val convertX = x.map(value => Try(value.toInt))
val convertY = y.map(value => Try(value.toBoolean))
val convertZ = z.map(value => Try(value.toBoolean))
val failuresExist =
List(convertX, convertY, convertZ).flatten.exists(_.isFailure)
if (failuresExist) BadRequest("Cannot convert input")
else {
convertX.foreach {
case Success(value) => processX(value)
case _ =>
}
convertY.foreach {
case Success(value) => processY(value)
case _ =>
}
convertZ.foreach {
case Success(value) => processZ(value)
case _ =>
}
Ok()
}
}
Although this solution will probably work, it is very awkward. How can I improve it?
A more imperative style could work, if you don't mind that.
def f(x: Option[String], y: Option[String], z: Option[String]): Result = {
try {
val convertX = x.map(_.toInt)
val convertY = y.map(_.toBoolean)
val convertZ = z.map(_.toBoolean)
convertX.foreach(processX)
convertY.foreach(processY)
convertZ.foreach(processZ)
Ok()
} catch {
case _: IllegalArgumentException | _: NumberFormatException => BadRequest("Cannot convert input")
}
}
If you're using scalaz I would use the Option applicative and ApplicativeBuilder's |#| combinator. If any of the inputs are None, then the result is also None.
import scalaz.std.option.optionInstance
import scalaz.syntax.apply._
val result: Option[String] =
Some(1) |#| Some("a") |#| Some(true) apply {
(int, str, bool) =>
s"int is $int, str is $str, bool is $bool"
}
In pure scala, you could use flatMap on option:
val result: Option[String] =
for {
a <- aOpt
b <- bOpt
c <- cOpt
} yield s"$a $b $c"
I personally prefer the applicative because it makes it clear that the results are independent. for-blocks read to me like "first do this with a, then this with b, then this with c" whereas applicative style is more like "with all of a, b, and c, do ..."
Another option with scalaz is sequence, which inverts a structure like T[A[X]] into A[T[X]] for traversable T and applicative A.
import scalaz.std.option.optionInstance
import scalaz.std.list.listInstance
import scalaz.syntax.traverse._
val list: List[Option[Int]] = List(Option(1), Option(4), Option(5))
val result: Option[List[Int]] = list.sequence
// Some(List(1, 4, 5))
For completence I am adding the a piece of code here that process the values are required. However if this is better than that the original is debatable. If you want to process all the value and gather the results of the transformation scalaz Validator could be a better option.
import scala.util.Try
val x = Some("12")
val y = Some("false")
val z = Some("hello")
def process(v: Boolean) = println(s"got a $v")
def processx(v: Int) = println(s"got a number $v")
// Abstract the conversion to the appropriate mapping
def mapper[A, B](v: Option[String])(mapping: String => A)(func: Try[A] => B) = for {
cx <- v.map(vv => Try(mapping(vv)))
} yield func(cx)
def f(x: Option[String], y: Option[String], z: Option[String]) = {
//partially apply the function here. We will use that method twice.
def cx[B] = mapper[Int, B](x)(_.toInt) _
def cy[B] = mapper[Boolean, B](y)(_.toBoolean) _
def cz[B] = mapper[Boolean, B](z)(_.toBoolean) _
//if one of the values is a failure then return the BadRequest,
// else process each value and return ok
(for {
vx <- cx(_.isFailure)
vy <- cy(_.isFailure)
vz <- cz(_.isFailure)
if vx || vy || vz
} yield {
"BadRequest Cannot convert input"
}) getOrElse {
cx(_.map(processx))
cy(_.map(process))
cz(_.map(process))
"OK"
}
}
f(x,y,z)
In the case a "short circuit" behaviour is required the following code will work.
import scala.util.Try
val x = Some("12")
val y = Some("false")
val z = Some("hello")
def process(v: Boolean) = println(s"got a $v")
def processx(v: Int) = println(s"got a number $v")
def f(x: Option[String], y: Option[String], z: Option[String]) =
(for {
cx <- x.map(v => Try(v.toInt))
cy <- y.map(v => Try(v.toBoolean))
cz <- z.map(v => Try(v.toBoolean))
} yield {
val lst = List(cx, cy, cz)
lst.exists(_.isFailure) match {
case true => "BadRequest Cannot convert input"
case _ =>
cx.map(processx)
cy.map(process)
cz.map(process)
"OK"
}
}) getOrElse "Bad Request: missing values"
f(x,y,z)

How do I inherit shared code in a Scala unapply function?

I have Scala code with some boilerplate, and I figure it's Scala, so I must be doing something wrong. I need some help figuring out how to remove the redundancies.
trait Number {
val x: Int
}
case class EvenNumber(x: Int) extends Number
object EvenNumber {
def unapply(s: String): Option[EvenNumber] = {
val x = s.toInt
if (x % 2 == 0) Some(EvenNumber(x))
else None
}
}
case class OddNumber(x: Int) extends Number
object OddNumber {
def unapply(s: String): Option[OddNumber] = {
val x = s.toInt
if (x % 2 == 1) Some(OddNumber(x))
else None
}
}
In this simple example there are even numbers and odd numbers which are subtypes of a general number type. Both even and odd numbers have extractors that allow them to be created from strings. This enables use cases like the following.
scala> "4" match {case EvenNumber(n) => n;case _ => None}
// returns EvenNumber(4)
scala> "5" match {case EvenNumber(n) => n;case _ => None}
// returns None
scala> "4" match {case OddNumber(n) => n;case _ => None}
// returns None
scala> "5" match {case OddNumber(n) => n;case _ => None}
// returns OddNumber(5)
The source code for the two extractors is identical except for the result of the x % 2 operation (0 or 1) and the extracted type (EvenNumber or OddNumber). I'd like to be able to write the source once and parameterize on these two values, but I can't figure out how. I've tried various type parameterizations to no avail.
The Stackoverflow question "How to use extractor in polymorphic unapply?" is related but different, because my implementing classes are not distinguished by the types they contain by rather by the string inputs they recognize.
Here is a revised version of the code incorporating comments I received in addition to the original post. (As is often the case, the first round of answers helped me figure out what my real question was.)
import scala.util.Try
trait Number {
val x: Int
}
object NumberParser {
def parse[N <: Number](s: String, remainder: Int, n: Int => N): Option[N] =
Try {s.toInt}.toOption.filter(_ % 2 == remainder).map(n(_))
}
case class EvenNumber(x: Int) extends Number
object EvenNumber {
def unapply(s: String): Option[EvenNumber] = NumberParser.parse(s, 0, EvenNumber(_))
}
case class OddNumber(x: Int) extends Number
object OddNumber {
def unapply(s: String): Option[OddNumber] = NumberParser.parse(s, 1, OddNumber(_))
}
Factoring out a static NumberParser.parse function is a reasonable solution. I would still like to have have syntactic sugar that obviated my repeating unapply lines in all of my case classes, since in a more complicated example that had more than two that could get ugly. Does anyone know of a way to do this?
More crucially, the use case I really want to support is the following.
scala> "5" match {case EvenNumber(n) =>n;case OddNumber(n) => n;case _ => None}
// returns OddNumber(5)
scala> "4" match {case EvenNumber(n) =>n;case OddNumber(n) => n;case _ => None}
// returns EvenNumber(4)
scala> "x" match {case EvenNumber(n) =>n;case OddNumber(n) => n;case _ => None}
// returns None
Again this is fine for two cases, but in a different application where there are more than two it can become unmanageable. I want to write a single case
s match {case Number(n) => n; case _ => None}
which returns OddNumber(5), EvenNumber(4), None as above.
I can't figure out how to write my Number supertype to support this. Is it possible in Scala?
Edit: Wrote a description of my final answer with additional commentary in "Runtime Polymorphism with Scala Extractors".
Why inherit?
object Mod2Number {
def parse[A <: Number](s: String, i: Int, n: Int => A) = {
val x = s.toInt
if (x % 2 == i) Some(n(x))
else None
}
}
case class EvenNumber(x: Int) extends Number
object EvenNumber {
def unapply(s: String) = Mod2Number.parse(s, 0, n => EvenNumber(n))
}
But if even that is too much noise you can go one step further:
trait Makes[A <: Number] {
def apply(i: Int): A
def mod: Int
def unapply(s: String): Option[A] = {
val x = s.toInt
if (x % 2 == mod) Some(apply(x))
else None
}
}
case class EvenNumber(x: Int) extends Number
object EvenNumber extends Makes[EvenNumber] { def mod = 0 }
I guess you should catch exceptions on toInt - exceptions in pattern matching is something strange.
object EvenNumber {
def unapply(s: String): Option[Int] = Try{s.toInt}.toOption.filter{_ % 2 == 0}
}
object OddNumber {
def unapply(s: String): Option[Int] = Try{s.toInt}.toOption.filter{_ % 2 == 1}
}
You could extract similar code, but I don't think it's useful here:
class IntFilter(f: Int => Boolean) {
def unapply(s: String): Option[Int] = Try{s.toInt}.toOption.filter(f)
}
object EvenNumber extend IntFilter(_ % 2 == 0)
object OddNumber extend IntFilter(_ % 2 == 1)
For edited question:
s match {case Number(n) => n; case _ => None}
You could create object Number like this:
object Number{
def unapply(s: String): Option[Number] = Try{s.toInt}.toOption.collect{
case i if i % 2 == 0 => EvenNumber(i)
case i if i % 2 == 1 => OddNumber(i)
}
}

Chaining Scalaz validation functions: Function1[A,Validation[E,B]]

I'm trying to write some code to make it easy to chain functions that return Scalaz Validation types. One method I am trying to write is analogous to Validation.flatMap (Short circuit that validation) which I will call andPipe. The other is analogous to |#| on ApplicativeBuilder (accumulating errors) except it only returns the final Success type, which I will call andPass
Suppose I have functions:
def allDigits: (String) => ValidationNEL[String, String]
def maxSizeOfTen: (String) => ValidationNEL[String, String]
def toInt: (String) => ValidationNEL[String, Int]
As an example, I would like to first pass the input String to both allDigits and maxSizeOf10. If there are failures, it should short circuit by not calling the toInt function and return either or both failures that occurred. If Successful, I would like to pass the Success value to the toInt function. From there, it would either Succeed with the output value being an Int, or it would fail returning only the validation failure from toInt.
def intInput: (String) => ValidationNEL[String,Int] = (allDigits andPass maxSizeOfTen) andPipe toInt
Is there a way to do this without my add-on implementation below?
Here is my Implementation:
trait ValidationFuncPimp[E,A,B] {
val f: (A) => Validation[E, B]
/** If this validation passes, pass to f2, otherwise fail without accumulating. */
def andPipe[C](f2: (B) => Validation[E,C]): (A) => Validation[E,C] = (a: A) => {
f(a) match {
case Success(x) => f2(x)
case Failure(x) => Failure(x)
}
}
/** Run this validation and the other validation, Success only if both are successful. Fail accumulating errors. */
def andPass[D](f2: (A) => Validation[E,D])(implicit S: Semigroup[E]): (A) => Validation[E,D] = (a:A) => {
(f(a), f2(a)) match {
case (Success(x), Success(y)) => Success(y)
case (Failure(x), Success(y)) => Failure(x)
case (Success(x), Failure(y)) => Failure(y)
case (Failure(x), Failure(y)) => Failure(S.append(x, y))
}
}
}
implicit def toValidationFuncPimp[E,A,B](valFunc : (A) => Validation[E,B]): ValidationFuncPimp[E,A,B] = {
new ValidationFuncPimp[E,A,B] {
val f = valFunc
}
}
I'm not claiming that this answer is necessarily any better than drstevens's, but it takes a slightly different approach and wouldn't fit in a comment there.
First for our validation methods (note that I've changed the type of toInt a bit, for reasons I'll explain below):
import scalaz._, Scalaz._
def allDigits: (String) => ValidationNEL[String, String] =
s => if (s.forall(_.isDigit)) s.successNel else "Not all digits".failNel
def maxSizeOfTen: (String) => ValidationNEL[String, String] =
s => if (s.size <= 10) s.successNel else "Too big".failNel
def toInt(s: String) = try(s.toInt.right) catch {
case _: NumberFormatException => NonEmptyList("Still not an integer").left
}
I'll define a type alias for the sake of convenience:
type ErrorsOr[+A] = NonEmptyList[String] \/ A
Now we've just got a couple of Kleisli arrows:
val validator = Kleisli[ErrorsOr, String, String](
allDigits.flatMap(x => maxSizeOfTen.map(x *> _)) andThen (_.disjunction)
)
val integerizer = Kleisli[ErrorsOr, String, Int](toInt)
Which we can compose:
val together = validator >>> integerizer
And use like this:
scala> together("aaa")
res0: ErrorsOr[Int] = -\/(NonEmptyList(Not all digits))
scala> together("12345678900")
res1: ErrorsOr[Int] = -\/(NonEmptyList(Too big))
scala> together("12345678900a")
res2: ErrorsOr[Int] = -\/(NonEmptyList(Not all digits, Too big))
scala> together("123456789")
res3: ErrorsOr[Int] = \/-(123456789)
Using flatMap on something that isn't monadic makes me a little uncomfortable, and combining our two ValidationNEL methods into a Kleisli arrow in the \/ monad—which also serves as an appropriate model for our string-to-integer conversion—feels a little cleaner to me.
This is relatively concise with little "added code". It is still sort of wonky though because it ignores the successful result of applying allDigits.
scala> val validated = for {
| x <- allDigits
| y <- maxSizeOfTen
| } yield x *> y
validated: String => scalaz.Validation[scalaz.NonEmptyList[String],String] = <function1>
scala> val validatedToInt = (str: String) => validated(str) flatMap(toInt)
validatedToInt: String => scalaz.Validation[scalaz.NonEmptyList[String],Int] = <function1>
scala> validatedToInt("10")
res25: scalaz.Validation[scalaz.NonEmptyList[String],Int] = Success(10)
Alternatively you could keep both of the outputs of allDigits and maxSizeOfTen.
val validated2 = for {
x <- allDigits
y <- maxSizeOfTen
} yield x <|*|> y
I'm curious if someone else could come up with a better way to combine these. It's not really composition...
val validatedToInt = (str: String) => validated2(str) flatMap(_ => toInt(str))
Both validated and validated2 accumulate failures as shown below:
scala> def allDigits: (String) => ValidationNEL[String, String] = _ => failure(NonEmptyList("All Digits Fail"))
allDigits: String => scalaz.Scalaz.ValidationNEL[String,String]
scala> def maxSizeOfTen: (String) => ValidationNEL[String, String] = _ => failure(NonEmptyList("max > 10"))
maxSizeOfTen: String => scalaz.Scalaz.ValidationNEL[String,String]
scala> val validated = for {
| x <- allDigits
| y <- maxSizeOfTen
| } yield x *> y
validated: String => scalaz.Validation[scalaz.NonEmptyList[String],String] = <function1>
scala> val validated2 = for {
| x <- allDigits
| y <- maxSizeOfTen
| } yield x <|*|> y
validated2: String => scalaz.Validation[scalaz.NonEmptyList[String],(String, String)] = <function1>
scala> validated("ten")
res1: scalaz.Validation[scalaz.NonEmptyList[String],String] = Failure(NonEmptyList(All Digits Fail, max > 10))
scala> validated2("ten")
res3: scalaz.Validation[scalaz.NonEmptyList[String],(String, String)] = Failure(NonEmptyList(All Digits Fail, max > 10))
Use ApplicativeBuilder with the first two, so that the errors accumulate,
then flatMap toInt, so toInt only gets called if the first two succeed.
val validInt: String => ValidationNEL[String, Int] =
for {
validStr <- (allDigits |#| maxSizeOfTen)((x,_) => x);
i <- toInt
} yield(i)