Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Missing Functor and Monad instances when using scala.concurrent.Future with EitherT

I'm trying to use Scalaz EitherT with a scala.concurrent.Future. When trying to use it in a for-comprehension:

import scalaz._
import Scalaz._

val et1:EitherT[Future, String, Int] = EitherT(Future.successful(1.right))

val et2:EitherT[Future, String, String] = EitherT(Future.successful("done".right))

val r:EitherT[Future, String, String] = for {
    a <- et1
    b <- et2
} yield (s"$a $b")

I get the following missing Functor and Monad instances error:

could not find implicit value for parameter F: scalaz.Functor[scala.concurrent.Future]
b <- et2
  ^
could not find implicit value for parameter F: scalaz.Monad[scala.concurrent.Future]
a <- et1

Does scalaz define instances for Functor and Monad for Future? If not are there any other libraries that provide these instances or do I need to write them?

like image 595
ssanj Avatar asked Dec 01 '22 13:12

ssanj


2 Answers

You need an implicit ExecutionContext in scope. import ExecutionContext.Implicits.global will get you the global execution context.

Full example:

  import scala.concurrent.ExecutionContext.Implicits.global

  import scalaz._
  import Scalaz._

  val et1:EitherT[Future, String, Int] = EitherT(Future.successful(1.right))

  val et2:EitherT[Future, String, String] = EitherT(Future.successful("done".right))

  val r:EitherT[Future, String, String] = for {
    a <- et1
    b <- et2
  } yield s"$a $b"

  val foo = Await.result(r.run, 1 seconds)
  // => \/-("1 done")
like image 97
danielnixon Avatar answered Dec 04 '22 03:12

danielnixon


The error is not because of ExecutionContext is missing (it's needed though) but because Scala Future is not a Functor nor a Monad.

The accepted solution works not because of the ExecutionContext but because it imports all the implicits from Scalaz.

This is the line that really fix the problem:

import Scalaz._

Also note that using the global execution context it's ok for a test but should not be used on production deployments.

The problem with that solution is that you import ALL the implicits defined on the library and can make your IDE little bit slow.

On version 7 Scalaz offer the option to import only what you need, using the package scalaz.syntax.

Same previous solution with concrete imports:

import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._

import scalaz._
import scalaz.std.scalaFuture._
import scalaz.syntax.either._

val et1:EitherT[Future, String, Int] = EitherT(Future.successful(1.right))

val et2:EitherT[Future, String, String] = EitherT(Future.successful("done".right))

val r:EitherT[Future, String, String] = for {
  a <- et1
  b <- et2
} yield s"$a $b"

val foo = Await.result(r.run, 1 seconds)
foo: String \/ String = \/-(1 done)
like image 40
Carlos Verdes Avatar answered Dec 04 '22 03:12

Carlos Verdes