I quite often use the function below to convert Option[Try[_]] to Try[Option[_]] but it feels wrong. Can be such a functionality expressed in more idiomatic way?
def swap[T](optTry: Option[Try[T]]): Try[Option[T]] = {
optTry match {
case Some(Success(t)) => Success(Some(t))
case Some(Failure(e)) => Failure(e)
case None => Success(None)
}
}
Say I have two values:
val v1: Int = ???
val v2: Option[Int] = ???
I want to make an operation op (which can fail) on these values and pass that to function f below.
def op(x: Int): Try[String]
def f(x: String, y: Option[String]): Unit
I typically use for comprehension for readability:
for {
opedV1 <- op(v1)
opedV2 <- swap(v2.map(op))
} f(opedV1, opedV2)
PS. I'd like to avoid some heavy stuff like scalaz.
The cats library allows you to sequence an Option to a Try very easily:
scala> import cats.implicits._
import cats.implicits._
scala> import scala.util.{Failure, Success, Try}
import scala.util.{Failure, Success, Try}
scala> Option(Success(1)).sequence[Try, Int]
res0: scala.util.Try[Option[Int]] = Success(Some(1))
scala> Option(Failure[Int](new IllegalArgumentException("nonpositive integer"))).sequence[Try, Int]
res1: scala.util.Try[Option[Int]] = Failure(java.lang.IllegalArgumentException: nonpositive integer)
scala> None.sequence[Try, Int]
res2: scala.util.Try[Option[Int]] = Success(None)
Sounds like Try { option.map(_.get) } will do what you want.
This variant avoids rethrowing:
import scala.util.{Failure, Success, Try}
def swap[T](optTry: Option[Try[T]]): Try[Option[T]] =
optTry.map(_.map(Some.apply)).getOrElse(Success(None))
swap(Some(Success(1)))
// res0: scala.util.Try[Option[Int]] = Success(Some(1))
swap(Some(Failure(new IllegalStateException("test"))))
// res1: scala.util.Try[Option[Nothing]] = Failure(java.lang.IllegalStateException: test)
swap(None)
// res2: scala.util.Try[Option[Nothing]] = Success(None)
Related
I have the following function:
def function(i: Int): IO[Either[String, Option[Int]]] = ???
I want a function of the form:
def foo(either: Either[String, Option[Int]]): IO[Either[String, Option[Int]]]
and I want it to have the following behavior:
def foo1(either: Either[String, Option[Int]])
: IO[Either[String, Option[Int]]] = either match {
case Right(Some(i)) => bar(i)
case Right(None) => IO.pure(None.asRight)
case Left(s) => IO.pure(s.asLeft)
}
I want to do it less explicitly, so I tried EitherT:
def foo2(either: Either[String, Option[Int]]):
IO[Either[String, Option[Int]]] = {
val eitherT = for {
maybe <- EitherT.fromEither[IO](either)
int <- EitherT.fromOption(maybe, "???")
x <- EitherT(bar(int))
} yield x
eitherT.value
}
but this means that Right(None) will be mapped to IO(Left("???")) which is not what I want.
is there an alternative formulation with EitherT without a match expression that is equivalent to the foo1 implementation?
more importantly, how would an implementation that uses map/traverse/biTraverse/etc. (and doesn't match on any of option/eithers) look like?
p.s. The intention here is to define a "map" function for the following type:
trait Lookup[F[_], K, A] {
def get(key: K): F[Either[FormatError, Option[A]]]
}
without match
import cats._
import cats.data._
import cats.implicits._
def bar[F[_] : Applicative](i: Int): F[Either[String, Option[Int]]] =
(i + 1).some.asRight[String].pure[F]
def foo[F[_] : Applicative : Monad : FlatMap](either: Either[String, Option[Int]]): F[Either[String, Option[Int]]] =
OptionT(EitherT(either.pure[F])).flatMap { i =>
OptionT(EitherT(bar[F](i)))
}.value.value
foo[Id](1.some.asRight)
//res0: cats.Id[Either[String,Option[Int]]] = Right(Some(2))
import cats.Applicative
import cats.syntax.applicative._
def bar[F[_]](i: Int): F[Either[String, Option[Int]]] = ???
def foo[F[_] : Applicative](either: Either[String, Option[Int]]): F[Either[String, Option[Int]]] =
either match {
case Right(Some(i)) => bar(i)
case a => a.pure[F]
}
With MonadError we can:
eliminate 1 transformer during business logic implementation, so only OptionT is needed in def foo
do not make decision upfront how we want to handle errors, so user should choose concrete EitherT:
import cats._
import cats.data._
import cats.implicits._
import monix.eval._
type ErrorHandler[F[_]] = MonadError[F, String]
def bar[F[_] : ErrorHandler : Applicative](i: Int): F[Option[Int]] =
if (i > 0) (i + 1).some.pure[F] else implicitly[ErrorHandler[F]].raiseError("error")
def foo[F[_] : ErrorHandler : Applicative : FlatMap](option: Option[Int]): F[Option[Int]] =
OptionT(option.pure[F]).flatMap { i =>
OptionT(bar[F](i))
}.value
type Effect[A] = EitherT[Task, String, A]
import monix.execution.Scheduler.Implicits.global
foo[Effect](1.some).value.runSyncUnsafe()
//Either[String, Option[Int]] = Right(Some(2))
foo[Effect](0.some).value.runSyncUnsafe()
//Either[String, Option[Int]] = Left("error")
foo[Effect](none).value.runSyncUnsafe()
//Right(None)
Given
a value of type Any
a TypeTag corresponding to the desired type
How can I cast the value
Unfortunately, the following snippet doesn't compile
val v: Any = 123
val tag = typeTag[Int]
val i = v.asInstanceOf[t.tpe]
Use this
import scala.reflect.ClassTag
def getTypedArg[T: ClassTag](any: Any): Option[T] = {
any match {
case t: T => Some(t)
case invalid =>
None
}
}
Usage
scala> getTypedArg[Int](5)
res1: Option[Int] = Some(5)
scala> getTypedArg[Int]("str")
res2: Option[Int] = None
Source: Retrieve class-name from ClassTag
EDIT-1
As asked by #Aki, it can be made to work with TypeTags too, with this hack
import reflect.runtime.universe._
import scala.reflect.ClassTag
def typeToClassTag[T: TypeTag]: ClassTag[T] = {
ClassTag[T]( typeTag[T].mirror.runtimeClass( typeTag[T].tpe ) )
}
def getTypedArg2[T: TypeTag](any: Any): Option[T] = {
implicit val c: ClassTag[T] = typeToClassTag[T]
any match {
case t: T => Some(t)
case invalid =>
None
}
}
Reference: How to get ClassTag form TypeTag, or both at same time?
You could write your own method that does the casting.
(note that this method will never throw ClassCastExceptions)
def cast[A](a: Any, tag: TypeTag[A]): A = a.asInstanceOf[A]
Is there a way to convert a
Either[A, Future[B]]
to a
Future[Either[A, B]]
I have in mind something like the Future.sequence method which converts from a List[Future] to a Future[List]
Not sure there's an out of the box solution, this is what I came up with:
def foldEitherOfFuture[A, B](e: Either[A, Future[B]]): Future[Either[A, B]] =
e match {
case Left(s) => Future.successful(Left(s))
case Right(f) => f.map(Right(_))
}
In addition to catch eventual exception from the Future you can add a recover and map it to a Left:
case Right(f) => f.map(Right(_)).recover { case _ => Left(/** some error*/) }
There is no api functional call to do that. I'd try something like this:
def getResult[A, B]: Either[A, Future[B]] = ???
val res = getResult.fold(fa = l => Future(Left(l)), fb = r => r.map(value => Right(value)))
If you're using scalaz, you can just use sequenceU
import scala.concurrent.ExecutionContext.Implicits.global
import scalaz._
import Scalaz._
val x: Either[String, Future[Int]] = ???
val y: Future[Either[String, Int]] = x.sequenceU
Update (August 2019):
If you're using cats, use sequence:
import cats.implicits._
import scala.concurrent.ExecutionContext.Implicits.global
val x: Either[String, Future[Int]] = ???
val y: Future[Either[String, Int]] = x.sequence
Dumonad adds a set of extension methods to ease of reactive programming:
import io.github.dumonad.dumonad.Implicits._
val eitherOfFuture: Either[L,Future[R]]
val futureOfEither: Future[Either[L,R]] = eitherOfFuture.extractFuture
Is it possible to 'invert' a Scala Future?
Sometimes the result of a Future being a Success means an error. In that case it would be nice to flip a Future, i.e. call a function that returns a Future, which succeeds with a specified value if the original Future fails and fails with a specified Error in case the original Future succeeds.
def flip[T](original: Future[T])(value: => T)(error: Throwable): Future[T] = ???
def craziness[A](future: Future[A])(default : => A)(error: Throwable)(implicit ec: ExecutionContext): Future[A] = {
val p = Promise[A]()
import scala.util.{Success, Failure, Try}
future.onComplete {
case _: Success[_] => p.failure(error)
case _: Failure[_] => p.complete(Try(default))
}
p.future
}
Here's a repl session showing it work:
scala> val f1 = craziness[String](Future("hello!"))("my crazy default")(new Throwable("boom"))
f1: scala.concurrent.Future[String] = scala.concurrent.impl.Promise$DefaultPromise#4d154ccd
scala> f1 onComplete { println }
Failure(java.lang.Throwable: boom)
scala> val f2 = craziness[String](Future(throw new Exception("boom!")))("my crazy default")(new Throwable("boom"))
f2: scala.concurrent.Future[String] = scala.concurrent.impl.Promise$DefaultPromise#1890516e
scala> f2 onComplete { println }
Success(my crazy default)
EDIT:
for completeness, def craziness[A](future: Future[A]) should probably be def craziness[A](future: => Future[A])
I think you are after recover and recoverWith constructs. Here's a quick REPL session to show its usage.
$ scala
Welcome to Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_45).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import scala.concurrent.Future
import scala.concurrent.Future
scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global
scala> val failFuture = Future(sys.error("BOOM"))
failFuture: scala.concurrent.Future[Nothing] = scala.concurrent.impl.Promise$DefaultPromise#6e06451e
scala> val defaultValue = 100
defaultValue: Int = 100
scala> val futureRecoveredWithDefaultFuture = failFuture.recoverWith { case e: RuntimeException => Future.successful(defaultValue) }
futureRecoveredWithDefaultFuture: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise#130161f7
scala> val futureRecoveredWithDefaultValue = failFuture.recover { case e: RuntimeException => defaultValue }
futureRecoveredWithDefaultValue: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise#3b69e7d1
Checking if this really works:
scala> import scala.concurrent.duration._
import scala.concurrent.duration._
scala> import scala.concurrent.Await
import scala.concurrent.Await
scala> val res1 = Await.result(futureRecoveredWithDefaultFuture, 1.second)
res1: Int = 100
scala> val res2 = Await.result(futureRecoveredWithDefaultValue, 1.second)
res2: Int = 100
In Scala 2.12 you'll be able to use transform and transformWith to make this trivial.
But until then this should get you there:
implicit class InvertFuture[T](val fut: Future[T]) extends AnyVal {
def flip(recover: Throwable => T)(fail: T => Throwable)(implicit ec: ExecutionContext): Future[T] =
fut.recover({ case t => recover(t) }).map(t => throw fail(t))
}
// And usage:
scala> Future(1).flip(_ => 2)(_ => throw new IllegalStateException("ohnoes!")) onComplete println
Failure(java.lang.IllegalStateException: ohnoes!)
Suppose I need to convert a String to Int in Scala. If the string is not a number I would like to return None rather than throw an exception.
I found the following solution
def toMaybeInt(s:String) = {
import scala.util.control.Exception._
catching(classOf[NumberFormatException]) opt s.toInt
}
Does it make sense ? Would you change/improve it ?
I'd use scala.util.Try which returns Success or Failure for a computation that may throw an exception.
scala> val zero = "0"
zero: String = 0
scala> val foo = "foo"
foo: String = foo
scala> scala.util.Try(zero.toInt)
res5: scala.util.Try[Int] = Success(0)
scala> scala.util.Try(foo.toInt)
res6: scala.util.Try[Int] = Failure(java.lang.NumberFormatException: For input string: "foo")
So, toMaybeInt(s: String) becomes:
def toMaybeInt(s:String) = {
scala.util.Try(s.toInt)
}
For getting an option in any case, regardless of possible exceptions due to number malformation,
import scala.util.Try
def toOptInt(s:String) = Try(s.toInt) toOption
Then
scala> toOptInt("123")
res2: Option[Int] = Some(123)
scala> toOptInt("1a23")
res3: Option[Int] = None
Further, consider
implicit class convertToOptInt(val s: String) extends AnyVal {
def toOptInt() = Try(s.toInt) toOption
}
Hence
scala> "123".toOptInt
res5: Option[Int] = Some(123)
scala> "1a23".toOptInt
res6: Option[Int] = None