Suppose I have a function to check a string:
case class MyError(msg: String)
val oops = MyError("oops")
def validate(s: String):Either[MyError, Unit] =
if (s == "a") Right(()) else Left(oops)
Now I would like to reuse it and write a new function to check the head of a list of strings and return either an error or the list tail.
// should be validateHeadOfList but I don't want to change the name now
def validateList(xs: List[String]): Either[MyError, List[String]] =
xs match {
case head::tail =>
validate(head).fold(err => Left(err), _ => Right(tail))
case _ => Left(oops)
}
This function works but doesn't look elegant. How would you improve it ?
Your implementation looks rather idiomatic to me, but if you're looking for a possibly more concise alternative - I think this does exactly the same, and is (arguably) more concise:
def validateList(xs: List[String]): Either[MyError, List[String]] =
xs.headOption.map(validate).map(_.right.map(_ => xs.tail)).getOrElse(Left(oops))
Assuming you actually want to return either a single error or the original list, then the following will work. I can't comment on whether this is idiomatic Scala though.
case class MyError(msg: String)
val oops = MyError("oops")
def validate(s: String): Either[MyError, Unit] =
if (s == "a") ().asRight else oops.asLeft
final def validateList(list: List[String]): Either[MyError, List[String]] = {
#scala.annotation.tailrec
def loop(xs: List[String]): Either[MyError, List[String]] = {
xs match {
case head :: tail =>
validate(head) match {
case Left(error) => error.asLeft
case _ => loop(tail)
}
case _ => list.asRight
}
}
loop(list)
}
For example:
scala> validateList(List("a", "a", "a"))
res0: Either[MyError,List[String]] = Right(List(a, a, a))
scala> validateList(List("a", "b", "a"))
res1: Either[MyError,List[String]] = Left(MyError(oops))
Related
Suppose I am refactoring a function like this:
def check(ox: Option[Int]): Unit = ox match {
case None => throw new Exception("X is missing")
case Some(x) if x < 0 => throw new Exception("X is negative")
case _ => ()
}
I'd like to get rid of the exceptions but I need to keep the check signature and behavior as is, so I'm factoring out a pure implementation -- doCheck:
import scala.util.{Try, Success, Failure}
def doCheck(ox: Option[Int]): Try[Unit] = ???
def check(ox: Option[Int]): Unit = doCheck(ox).get
Now I am implementing doCheck as follows:
def doCheck(ox: Option[Int]): Try[Unit] = for {
x <- ox toTry MissingX()
_ <- (x > 0) toTry NegativeX(x)
} yield ()
Using the following implicits:
implicit class OptionTry[T](o: Option[T]) {
def toTry(e: Exception): Try[T] = o match {
case Some(t) => Success(t)
case None => Failure(e)
}
}
implicit class BoolTry(bool: Boolean) {
def toTry(e: Exception): Try[Unit] = if (bool) Success(Unit) else Failure(e)
}
The implicits certainly add more code. I hope to replace OptionTry with an implicit from scalaz/cats someday and maybe find an analog for BoolTry.
You could refactor with a loan pattern and Try.
def withChecked[T](i: Option[Int])(f: Int => T): Try[T] = i match {
case None => Failure(new java.util.NoSuchElementException())
case Some(p) if p >= 0 => Success(p).map(f)
case _ => Failure(
new IllegalArgumentException(s"negative integer: $i"))
}
Then it can be used as following.
val res1: Try[String] = withChecked(None)(_.toString)
// res1 == Failure(NoSuchElement)
val res2: Try[Int] = withChecked(Some(-1))(identity)
// res2 == Failure(IllegalArgumentException)
def foo(id: Int): MyType = ???
val res3: Try[MyType] = withChecked(Some(2)) { id => foo(id) }
// res3 == Success(MyType)
Is it possible to pattern match on function heads in scala?
For example, can I write something along the lines of:
def myFunction(a:: b:: xs): Int = ???
def myFunction(a:: xs): Int = ???
def myFunction(List.empty): Int = ???
You can use partial functions for this case. Example:
val myFunctionCase1: PartialFunction[List[Int], Int] = {
case a :: b :: xs => ???
}
val myFunctionCase2: PartialFunction[List[Int], Int] = {
case a :: xs => ???
}
val myFunctionCase3: PartialFunction[List[Int], Int] = {
case Nil => ???
}
// compose functions
val myFunction: List[Int] => Int =
myFunctionCase1 orElse myFunctionCase2 orElse myFunctionCase3
Usage examples:
myFunctionCase1(List(1,2,3)) // invoke
myFunctionCase1(List(1)) // throw MatchError
myFunctionCase2(List(1)) // invoke
...
myFunction(List(1,2,3))
myFunction(List(1))
myFunction(Nil)
...
Given the following method,
scala> def f(x: Option[String]): Either[String, Int] = x match {
case Some(x) => try { Right(x.toInt) }
catch {
case _: NumberFormatException => Left(s"Not an int: $x")
}
case None => Left("No String present.")
}
f: (x: Option[String])Either[String,Int]
testing
scala> f(None)
res0: Either[String,Int] = Left(No String present.)
scala> f(Some("44"))
res2: Either[String,Int] = Right(44)
scala> f(Some("zipp"))
res3: Either[String,Int] = Left(Not an int: zipp)
How would a Monad transformer be used here?
Note - I don't know if it's a good example since it's so short (and the pattern match might be the cleanest way), but I'm curious anyway.
How can I change list of Eithers into two list of value Right and Left. When I use partition it returns two lists of Either's not values. What is the simplest way to do it?
foldLeft allows you to easily write your own method:
def separateEithers[T, U](list: List[Either[T, U]]) = {
val (ls, rs) = list.foldLeft(List[T](), List[U]()) {
case ((ls, rs), Left(x)) => (x :: ls, rs)
case ((ls, rs), Right(x)) => (ls, x :: rs)
}
(ls.reverse, rs.reverse)
}
You'll have to map the two resulting lists after partitioning.
val origin: List[Either[A, B]] = ???
val (lefts, rights) = origin.partition(_.isInstanceOf[Left[_]])
val leftValues = lefts.map(_.asInstanceOf[Left[A]].a)
val rightValues = rights.map(_.asInstanceOf[Right[B]].b)
If you are not happy with the casts and isInstanceOf's, you can also do it in two passes:
val leftValues = origin collect {
case Left(a) => a
}
val rightValues = origin collect {
case Right(b) => b
}
And if you are not happy with the two passes, you'll have to do it "by hand":
def myPartition[A, B](origin: List[Either[A, B]]): (List[A], List[B]) = {
val leftBuilder = List.newBuilder[A]
val rightBuilder = List.newBuilder[B]
origin foreach {
case Left(a) => leftBuilder += a
case Right(b) => rightBuilder += b
}
(leftBuilder.result(), rightBuilder.result())
}
Finally, if you don't like mutable state, you can do so:
def myPartition[A, B](origin: List[Either[A, B]]): (List[A], List[B]) = {
#tailrec
def loop(xs: List[Either[A, B]], accLeft: List[A],
accRight: List[B]): (List[A], List[B]) = {
xs match {
case Nil => (accLeft.reverse, accRight.reverse)
case Left(a) :: xr => loop(xr, a :: accLeft, accRight)
case Right(b) :: xr => loop(xr, accLeft, b :: accRight)
}
}
loop(origin, Nil, Nil)
}
If making two passes through the list is okay for you, you can use collect:
type E = Either[String, Int]
val xs: List[E] = List(Left("foo"), Right(1), Left("bar"), Right(2))
val rights = xs.collect { case Right(x) => x}
// rights: List[Int] = List(1, 2)
val lefts = xs.collect { case Left(x) => x}
// lefts: List[String] = List(foo, bar)
Using for comprehensions, like this,
for ( Left(v) <- xs ) yield v
and
for ( Right(v) <- xs ) yield v
How to create a list with the same element n-times ?
Manually implementnation:
scala> def times(n: Int, s: String) =
| (for(i <- 1 to n) yield s).toList
times: (n: Int, s: String)List[String]
scala> times(3, "foo")
res4: List[String] = List(foo, foo, foo)
Is there also a built-in way to do the same ?
See scala.collection.generic.SeqFactory.fill(n:Int)(elem: =>A) that collection data structures, like Seq, Stream, Iterator and so on, extend:
scala> List.fill(3)("foo")
res1: List[String] = List(foo, foo, foo)
WARNING It's not available in Scala 2.7.
(1 to n).map( _ => "foo" )
Works like a charm.
Using tabulate like this,
List.tabulate(3)(_ => "foo")
I have another answer which emulates flatMap I think (found out that this solution returns Unit when applying duplicateN)
implicit class ListGeneric[A](l: List[A]) {
def nDuplicate(x: Int): List[A] = {
def duplicateN(x: Int, tail: List[A]): List[A] = {
l match {
case Nil => Nil
case n :: xs => concatN(x, n) ::: duplicateN(x, xs)
}
def concatN(times: Int, elem: A): List[A] = List.fill(times)(elem)
}
duplicateN(x, l)
}
}
def times(n: Int, ls: List[String]) = ls.flatMap{ List.fill(n)(_) }
but this is rather for a predetermined List and you want to duplicate n times each element