ssanj
ssanj

Reputation: 2179

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?

Upvotes: 5

Views: 4199

Answers (2)

Carlos Verdes
Carlos Verdes

Reputation: 3147

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)

Upvotes: 2

danielnixon
danielnixon

Reputation: 4268

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")

Upvotes: 17

Related Questions