Suppose I have the following setting:
def foo: Either[Error, A] = ???
def bar: EitherT[Future, Error, B] = ???
case class Baz(a: A, b: B)
How can I use for comprehension to instantiate the class Baz? I tried with:
val res = for {
a <- foo
b <- bar
} yield Baz(a, b)
but, the result has type Either[Error, Nothing]. I don't know what is the right return type in this case, but obviously I don't want Nothing...
What is the right way to combine Either and EitherT in for comprehension?
Use EitherT.fromEither function to create EitherT from Either
import cats.data._
import cats.implicits._
def foo[A]: Either[Error, A] = ???
def bar[B]: EitherT[Future, Error, B] = ???
case class Baz[A, B](a: A, b: B)
def res[A, B] = for {
a <- EitherT.fromEither[Future](foo[A])
b <- bar[B]
} yield Baz(a, b)
Related
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 know I can traverse Lists
import cats.instances.list._
import cats.syntax.traverse._
def doMagic(item: A): M[B] = ???
val list: List[A] = ???
val result: M[List[B]] = list.traverse(doMagic)
And I can convert a Seq back and forth to List
val seq: Seq[A] = ???
val result: M[Seq[B]] = seq.toList.traverse(doMagic).map(_.toSeq)
But can I also traverse Seq without the boilerplate?
val seq: Seq[A] = ???
val result: M[Seq[B]] = seq.traverse(doMagic)
Or what's an easy way to get an instance of Traverse[Seq]?
Cats does not provide typeclass instances for Seq, so besides implementing it yourself you're stuck with the conversion.
As to why, there's an ongoing discussion in an (somewhat old) Cats issue. To sum it up, you won't know enough about Seq underlying characteristics to make sure some of the typeclasses instances laws hold.
EDIT : Nevermind, it exists now, see linked thread
As of cats 2.3, support for immutable.Seq is now built in. See "Where are implicit instances for Seq?" on the FAQ or this PR where the functionality was added.
If you are absolutely sure that the conversion from all Seq to List will always succeed in your code, you can simply transfer the Traverse structure from List to Seq over an (pseudo-)isomorphism:
def traverseFromIso[F[_], Z[_]]
(forward: F ~> Z, inverse: Z ~> F)
(implicit zt: Traverse[Z])
: Traverse[F] = new Traverse[F] {
def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) ⇒ B): B = zt.foldLeft(forward(fa), b)(f)
def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
zt.foldRight(forward(fa), lb)(f)
def traverse[G[_], A, B]
(fa: F[A])
(f: (A) ⇒ G[B])
(implicit appG: Applicative[G])
: G[F[B]] = {
(zt.traverse(forward(fa))(f)(appG)).map(zb => inverse(zb))
}
}
This isn't really an isomorphism, because the conversion from Seq to List can fail badly (e.g. if the sequence is infinite). What it does is simply converting Seq to List back and forth, and forwarding all method calls to those of Traverse[List].
Now you can use this method to build an instance of Traverse[Seq]:
implicit val seqTraverse: Traverse[Seq] = traverseFromIso(
new FunctionK[Seq, List] { def apply[X](sx: Seq[X]): List[X] = sx.toList },
new FunctionK[List, Seq] { def apply[X](lx: List[X]): Seq[X] = lx }
)
Full code snippet (compiles with scala 2.12.4 and cats 1.0.1):
import cats._
import cats.implicits._
import cats.arrow.FunctionK
import scala.language.higherKinds
object TraverseFromIso {
// This method can build you a `Traversable[Seq]` from
// an `Traversable[List]` and a pair of polymorphic conversion
// functions:
def traverseFromIso[F[_], Z[_]]
(forward: F ~> Z, inverse: Z ~> F)
(implicit zt: Traverse[Z])
: Traverse[F] = new Traverse[F] {
def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) ⇒ B): B = zt.foldLeft(forward(fa), b)(f)
def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
zt.foldRight(forward(fa), lb)(f)
def traverse[G[_], A, B]
(fa: F[A])
(f: (A) ⇒ G[B])
(implicit appG: Applicative[G])
: G[F[B]] = {
(zt.traverse(forward(fa))(f)(appG)).map(zb => inverse(zb))
}
}
// A little demo
def main(args: Array[String]): Unit = {
// To instantiate a `Traverse[Seq]`, we have to provide
// two natural transformations (from List to Seq and back):
implicit val seqTraverse: Traverse[Seq] = traverseFromIso(
new FunctionK[Seq, List] { def apply[X](sx: Seq[X]): List[X] = sx.toList },
new FunctionK[List, Seq] { def apply[X](lx: List[X]): Seq[X] = lx }
)
// do stuff with `Traversable[Seq]` here
}
}
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
As the title mentions.
Having many operations done using EitherT[Future, A, B]. Sometimes I want map left or right through another operation having signature A => Future[C]. Other scenario is that EitherT[Future, A, B] the result of a mapping over a future resulting Future[EitherT[Future, A, B]].
How can I elegantly flatten types like:
EitherT[Future, Future[A], Future[B]] and Future[EitherT[Future, A, B]]
Thank you in advance.
In all your cases you can use EitherT#flatMap (or EitherT#flatMapF), in combination with lifting some value to EitherT (or disjunction (\/) with flatMapF).
Mapping a B => F[C] over an EitherT[F, A, B] :
flatMap + lift
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scalaz._, Scalaz._
def f(i: Int): Future[Double] = Future.successful(i.toDouble)
val r = EitherT.right[Future, String, Int](Future.successful(1))
r.flatMap(i => EitherT.right(f(i)))
// or
r.flatMapF(i => f(i).map(_.right))
Mapping a A => F[C] over an EitherT[F, A, B] :
swap + flatMap + lift
def g(s: String): Future[Int] = Future.successful(s.length)
val l = EitherT.left[Future, String, Int](Future.successful("error"))
l.swap.flatMap(s => EitherT.right(g(s))).swap
// or
l.swap.flatMap(s => EitherT.left[Future, Int, Int](g(s)))
// or
l.swap.flatMapF(s => g(s).map(_.left))
Mapping an A => Either[F, B, C] to an F[A] :
lift + flatMap
def h(i: Int): EitherT[Future, String, Int] =
EitherT.right(Future.successful(i + 1))
val fut = Future.successful(1)
// mapping gives us Future[EitherT[Future, String, Int]]
fut.map(h)
// lifting to EitherT and flatMap gives us EitherT[Future, String, Int]
EitherT.right(fut).flatMap(h)
As an exercise, I am trying to see if I can take a List[Any] and "cast" it into a case class using shapeless.
A very basic example of what I am trying to achieve:
case class Foo(i: Int, j: String)
val foo: Option[Foo] = fromListToCaseClass[Foo]( List(1:Any, "hi":Any) )
Here is how I am shaping my solution (this can be quite off):
def fromListToCaseClass[CC <: Product](a: List[Any]): Option[CC] = a.toHList[???].map( x => Generic[CC].from(x) )
Here is my reasoning:
I know that you can go from a case class to an HList[T] (CC -> HList[T]); where T is the type of the HList. I also know that you can create an HList from a list (list -> Option[HList]) as long as you know the type of the HList. Finally I know that you can go from an HList to a case class (HList -> CC).
CC -> HList[T]
list -> Option[HList[T]] -> Option[CC]
I am wondering if this makes sense or if I am way off here. Can we make this work? Any other suggestions? Thanks!
This can be done very straightforwardly using shapeless's Generic and FromTraversable type classes,
import scala.collection.GenTraversable
import shapeless._, ops.traversable.FromTraversable
class FromListToCaseClass[T] {
def apply[R <: HList](l: GenTraversable[_])
(implicit gen: Generic.Aux[T, R], tl: FromTraversable[R]): Option[T] =
tl(l).map(gen.from)
}
def fromListToCaseClass[T] = new FromListToCaseClass[T]
(There's some accidental complexity here due to Scala's awkwardness when it comes to mixing explicit and inferred type parameters: we want to specify T explicitly, but have R inferred for us).
Sample REPL session ...
scala> case class Foo(i: Int, j: String)
defined class Foo
scala> fromListToCaseClass[Foo](List(23, "foo"))
res0: Option[Foo] = Some(Foo(23,foo))
scala> fromListToCaseClass[Foo](List(23, false))
res1: Option[Foo] = None
You can do it with shapeless the following way:
import shapeless._
trait Creator[A] { def apply(list:List[Any]): Option[A] }
object Creator {
def as[A](list: List[Any])(implicit c: Creator[A]): Option[A] = c(list)
def instance[A](parse: List[Any] => Option[A]): Creator[A] = new Creator[A] {
def apply(list:List[Any]): Option[A] = parse(list)
}
def arbitraryCreate[A] = instance(list => list.headOption.map(_.asInstanceOf[A]))
implicit val stringCreate = arbitraryCreate[String]
implicit val intCreate = arbitraryCreate[Int]
implicit val hnilCreate = instance(s => if (s.isEmpty) Some(HNil) else None)
implicit def hconsCreate[H: Creator, T <: HList: Creator]: Creator[H :: T] =
instance {
case Nil => None
case list => for {
h <- as[H](list)
t <- as[T](list.tail)
} yield h :: t
}
implicit def caseClassCreate[C, R <: HList](
implicit gen: Generic.Aux[C, R],
rc: Creator[R]): Creator[C] =
instance(s => rc(s).map(gen.from))
}
And
val foo:Option[Foo] = Creator.as[Foo](List(1, "hi"))