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
Related
I'm reading the scala-with-cats book and follow it's exercise. When I come to the case study: data validation, I encounter some problems.
Here is my entire code (just the same with the book):
package org.scala.ch10.final_recap
import cats.Semigroup
import cats.data.Validated
import cats.data.Validated._
import cats.data.Kleisli
import cats.data.NonEmptyList
import cats.instances.either._
import cats.syntax.apply._
import cats.syntax.semigroup._
import cats.syntax.validated._
sealed trait Predicate[E, A] {
import Predicate._
def and(that: Predicate[E, A]): Predicate[E, A] =
And(this, that)
def or(that: Predicate[E, A]): Predicate[E, A] =
Or(this, that)
/**
* This part is for Kleislis
* #return
*/
def run(implicit s: Semigroup[E]): A => Either[E, A] =
(a: A) => this(a).toEither
def apply(a: A)(implicit s: Semigroup[E]): Validated[E, A] =
this match {
case Pure(func) =>
func(a)
case And(left, right) => (left(a), right(a)).mapN((_, _) => a)
case Or(left, right) =>
left(a) match {
case Valid(_) => Valid(a)
case Invalid(e1) =>
right(a) match {
case Valid(_) => Invalid(e1)
case Invalid(e2) => Invalid(e1 |+| e2)
}
}
}
}
object Predicate {
final case class And[E, A](left: Predicate[E, A], right: Predicate[E, A]) extends Predicate[E, A]
final case class Or[E, A](left: Predicate[E, A], right: Predicate[E, A]) extends Predicate[E, A]
final case class Pure[E, A](func: A => Validated[E, A]) extends Predicate[E, A]
def apply[E, A](f: A => Validated[E, A]): Predicate[E, A] = Pure(f)
def lift[E, A](err: E, fn: A => Boolean): Predicate[E, A] = Pure(a => if(fn(a)) a.valid else err.invalid)
}
object FinalRecapPredicate {
type Errors = NonEmptyList[String]
def error(s: String): NonEmptyList[String] = NonEmptyList(s, Nil)
type Result[A] = Either[Errors, A]
type Check[A, B] = Kleisli[Result, A, B]
def check[A, B](func: A => Result[B]): Check[A, B] = Kleisli(func)
def checkPred[A](pred: Predicate[Errors, A]): Check[A, A] =
Kleisli[Result, A, A](pred.run)
def longerThan(n: Int): Predicate[Errors, String] =
Predicate.lift(
error(s"Must be longer than $n characters"),
str => str.length > n
)
val alphanumeric: Predicate[Errors, String] =
Predicate.lift(
error(s"Must be all alphanumeric characters"),
str => str.forall(_.isLetterOrDigit)
)
def contains(char: Char): Predicate[Errors, String] =
Predicate.lift(
error(s"Must contain the character $char"),
str => str.contains(char)
)
def containsOnce(char: Char): Predicate[Errors, String] =
Predicate.lift(
error(s"Must contain the character $char only once"),
str => str.count(_ == char) == 1
)
val checkUsername: Check[String, String] = checkPred(longerThan(3) and alphanumeric)
val splitEmail: Check[String, (String, String)] = check(_.split('#') match {
case Array(name, domain) =>
Right((name, domain))
case _ =>
Left(error("Must contain a single # character"))
})
val checkLeft: Check[String, String] = checkPred(longerThan(0))
val checkRight: Check[String, String] = checkPred(longerThan(3) and contains('.'))
val joinEmail: Check[(String, String), String] =
check {
case (l, r) => (checkLeft(l), checkRight(r)).mapN(_ + "#" + _)
}
val checkEmail: Check[String, String] = splitEmail andThen joinEmail
final case class User(username: String, email: String)
def createUser(username: String, email: String): Either[Errors, User] =
(checkUsername.run(username),
checkEmail.run(email)).mapN(User)
def main(args: Array[String]): Unit = {
println(createUser("", "noel#underscore.io#io"))
}
}
It supposes the code should end up with the error message Left(NonEmptyList(Must be longer than 3 characters), Must contain a single # character) But what I actually is Left(NonEmptyList(Must be longer than 3 characters))
Obviously, it does not work as expected. It fails fast instead of accumulating errors... How to fix that plz? (I've spent hours now and can't get a workaround)
This is the "problematic" part:
def createUser(username: String, email: String): Either[Errors, User] =
(checkUsername.run(username),
checkEmail.run(email)).mapN(User)
You are combining a tuple of Results, where
type Result[A] = Either[Errors, A]
This means you are really doing a mapN on a pair of Eithers, an operation provided by the Semigroupal type class. This operation will not accumulate results.
There are several reasons for this, but one that I find particularly important is the preserving of behaviour if we find ourselves using a Semigroupal / Applicative which also happens to be a Monad. Why is that a problem? Because Monads are sequencing operations, making each step depend on the previous one, and having "fail early" semantics. When using some Monad, one might expect those semantics to be preserved when using constructs from the underlying Applicative (every Monad is also an Applicative). In that case, if the implementation of Applicative used "accumulation" semantics instead of "fail early" semantics, we would ruin some important laws like referential transparency.
You can use a parallel version of mapN, called parMapN, whose contract guarantees that the implementation will be evaluating all results in parallel. This means that it definitely cannot be expected to have the "fail early" semantics, and accumulating results is fine in that case.
Note that Validated accumulates results as well, usually in a NonEmptyList or a NonEmptyChain. This is probably why you expected to see your accumulated results; the only problem is, you were not using Validated values in the "problematic" part of your code, but raw Eithers instead.
Here's some simple code that demonstrates the above concepts:
import cats.data._
import cats.implicits._
val l1: Either[String, Int] = Left("foo")
val l2: Either[String, Int] = Left("bar")
(l1, l2).mapN(_ + _)
// Left(foo)
(l1, l2).parMapN(_ + _)
// Left(foobar)
val v1: ValidatedNel[String, Int] = l1.toValidatedNel
val v2: ValidatedNel[String, Int] = l2.toValidatedNel
(v1, v2).mapN(_ + _)
// Invalid(NonEmptyList(foo, bar))
I've started learning functional programming with Cats and I stuck with flatMapping (merging) applicatives F[List].
What is very simple in pure Scala is flatmapping list of lists like that:
val animals = List("Dog", "Cat", "Bird")
def getBreads(animal: String): List[String] = ...
val allAnimalsBreads = animals.flatMap(animal => getBread(animal)) // this will be just List[String]
How can I do the same if everything is wrapped with applicative?:
val animals = List("Dog", "Cat", "Bird").pure[F]
def getBreads(animal: String): F[List[String]] = ...
val allAnimalsBreads = ? // this should be F[List[String]]
Applicative provides ap and pure, but does not guarantee to provide flatMap, which is provided by Monad:
Monad extends the Applicative type class with a new function flatten.
If F was a monad, then at least in scalaz we might use ListT, for example,
import scalaz._
import ListT._
import scalaz.std.option._
val animals: Option[List[String]] = Some(List("Dog", "Cat", "Bird"))
def getBreeds(animal: String): Option[List[String]] = ???
(for {
animal <- listT(animals)
breed <- listT(getBreeds(animal))
} yield breed).run
However cats does not seem to provide ListT:
A naive implementation of ListT suffers from associativity issues; ... It’s possible to create a ListT that doesn’t
have these issues, but it tends to be pretty inefficient. For many
use-cases, Nested can be used to achieve the desired results.
Here is an attempt at a mad solution that you should not use. Consider Validated which only has Applicative instance. Let us provide a Monad instance even though Validated is not a Monad:
implicit def validatedMonad[E]: Monad[Validated[E, *]] =
new Monad[Validated[E, *]] {
def flatMap[A, B](fa: Validated[E, A])(f: A => Validated[E, B]): Validated[E, B] =
fa match {
case Valid(a) => f(a)
case i # Invalid(_) => i
}
def pure[A](x: A): Validated[E, A] = Valid(x)
def tailRecM[A, B](a: A)(f: A => Validated[E, Either[A, B]]) = ???
}
The implementation of validatedMonad is taken from scala-exercises.org/cats/validated.
Next let us make scalaz's listT available within cats via shims interop layer
libraryDependencies += "com.codecommit" %% "shims" % "2.1.0"
Putting it all together, we have
import cats._
import cats.Monad
import cats.data.Validated.{Invalid, Valid}
import cats.data.{Nested, OptionT, Validated, ValidatedNec}
import cats.implicits._
import scalaz.ListT._
import shims._
implicit def validatedMonad[E]: Monad[Validated[E, *]] =
new Monad[Validated[E, *]] {
def flatMap[A, B](fa: Validated[E, A])(f: A => Validated[E, B]): Validated[E, B] =
fa match {
case Valid(a) => f(a)
case i # Invalid(_) => i
}
def pure[A](x: A): Validated[E, A] = Valid(x)
def tailRecM[A, B](a: A)(f: A => Validated[E, Either[A, B]]) = ???
}
val animals: Validated[String, List[String]] = List("Dog", "Cat", "Bird").valid
def getBreeds(animal: String): Validated[String, List[String]] = ???
(for {
animal <- listT(animals)
breed <- listT(getBreeds(animal))
} yield breed).run
Note this "solution" breaks monadic laws, is not general, and is likely to cause confusion, so do not use it.
For Applicative this is impossible. For Monad if you don't want to use unconventional transformer ListT you can do
import cats.syntax.traverse._
import cats.syntax.applicative._
import cats.syntax.functor._
import cats.syntax.flatMap._
import cats.instances.list._
val allAnimalsBreads: F[List[String]] =
animals.map(_.map(getBreads)) // F[List[F[List[String]]]]
.map(_.sequence) // F[F[List[List[String]]]]
.flatten // F[List[List[String]]]
.map(_.flatten) // F[List[String]]
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:
import cats.syntax.cartesian._
type M[X] = Future[Either[Error, X]]
val ma: M[A] = ???
val mb: M[B] = ???
I know I can do that:
def doStuff(a: A, b: B): C = ???
val result: M[C] = (ma |#| mb).map(doStuff)
But how do I flatMap? There's no flatMap in the CartesianBuilders.
def doFancyStuff(a: A, b: B): M[C] = ???
val result: M[C] = (ma |#| mb).flatMap(doFancyStuff)
I think the main problem is that it's awkward to flatMap on a Future[Either[Error, X]] in the sense of EitherT[Future, Error, X]-monad stack, because the original flatMap of the Future gets in the way, and the compiler isn't looking for a monad instance that could handle the combination of Future and Either simultaneously. However, if you wrap the futures in EitherT, everything works smoothly.
For cats 1.0.1
In the following, (a,b).tupled corresponds to Cartesian.product(a, b), and (a, b).mapN corresponds to the deprecated (a |#| b).map.
Given types A, B, C, Error, the following code snippets compile under cats 1.0.1:
If you want to preserve your definition of M (you probably should), then you
can avoid the above mentioned problems by wrapping everything in EitherT and then
extracting the value:
import scala.util.Either
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global // required by Monad[Future]
import cats.instances.future._ // Monad for `Future`
import cats.syntax.apply._ // `tupled` and `mapN`
import cats.data.EitherT // EitherT monad transformer
type M[X] = Future[Either[Error, X]]
val ma: M[A] = ???
val mb: M[B] = ???
def doStuff(a: A, b: B): C = ???
val result1: M[C] = (EitherT(ma), EitherT(mb)).mapN(doStuff).value
def doFancyStuff(a: A, b: B): M[C] = ???
val result2: M[C] = (for {
ab <- (EitherT(ma), EitherT(mb)).tupled
c <- EitherT(doFancyStuff(ab._1, ab._2))
} yield c).value
However, if this seems too awkward, and you can adjust the definition of M,
the following variant could be slightly shorter:
import scala.util.Either
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global // required by Monad[Future]
import cats.instances.future._ // Monad for `Future`
import cats.syntax.apply._ // `tupled` and `mapN`
import cats.data.EitherT // EitherT monad transformer
type M[X] = EitherT[Future, Error, X]
val ma: M[A] = ??? // either adjust signatures, or wrap result in EitherT(res)
val mb: M[B] = ???
def doStuff(a: A, b: B): C = ???
val result1: M[C] = (ma, mb).mapN(doStuff)
def doFancyStuff(a: A, b: B): M[C] = ???
val result2: M[C] = (ma, mb).tupled.flatMap{
case (a, b) => doFancyStuff(a, b)
}
This is because (ma, mb).tupled builds a M[(A, B)], where M is the previously mentioned monad stack, which then can be easily flatMapped with a (A, B) => M[C] function to M[C].
For older versions with Cartesian (untested)
Assuming that (ma, mb).tupled corresponds to the deprecated Cartesian.product and (ma, mb).mapN corresponds to the deprecated (ma |#| mb).map, the two definitions of result1 and result2 in the above code snippet for 1.0.1 translate to:
val result1: M[C] = (ma |#| mb).map(doStuff)
val result2: M[C] = Cartesian[M].product(ma, mb).flatMap{
case (a, b) => doFancyStuff(a, b)
}
Again, this works only because Cartesian[M].product(ma, mb) builds an M[(A, B)] from M[A] and M[B], where M[X] is defined as EitherT[Future, Error, X]. If it were defined as Future[Either[Error, X]], then the flatMap would be invoked on the Future, and instead of doFancyStuff we would have to pass something like Either[Error, (A, B)] => Future[Either[Error, C]], which is probably not what you want.
I am looking at this question from Scala and Scalaz angles. OptionT works for Future but not Try. What is the reason there is no OptionT for Try where there is a usecase a function i.e. def foo(i: Int): Try[Option[Int]] = ... may or not return a value and occasionally network exception will happen? Thanks
The reason is Try isn't a valid functor.
You'll need to use scalaz-outlaws or write your own Try instances. Here's a working example using scalaz-outlaws' Try instances:
import scala.util.{Try,Success,Failure}
import scalaz._
import Scalaz._
implicit val tryOutlawInstances = new Traverse[Try] with Monad[Try] with Plus[Try]{
def point[A](a: ⇒ A): Try[A] = Success(a)
override def map[A,B](fa: Try[A])(f: A ⇒ B) = fa map f
def bind[A,B](fa: Try[A])(f: A ⇒ Try[B]) = fa flatMap f
def traverseImpl[F[_], A, B](fa: Try[A])(f: A ⇒ F[B])(implicit F: Applicative[F]) : F[Try[B]] = fa match {
case Success(a) ⇒ F.map(f(a))(Success.apply)
case Failure(f) ⇒ F.point(Failure(f))
}
def plus[A](a: Try[A], b: ⇒ Try[A]) = a orElse b
}
val foo = Try("foo".some)
val result = OptionT(foo).map(x => x.toUpperCase).run