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

2

5

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?

Tonguing answered 22/12, 2015 at 1:34 Comment(0)
K
17

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")
Kitts answered 22/12, 2015 at 2:22 Comment(5)
It works for me. I've updated my answer with the full working example.Kitts
yep, it works! I must have missed something when I tried before. Thanks.Tonguing
@danielnixon: When I changed your example to use \/-(1) instead of 1.right it failed. Do you know why this is? "no type parameters for method apply: (run: F[scalaz.\/[A,B]])scalaz.EitherT[F,A,B] in object EitherT exist so that it can be applied to arguments (scala.concurrent.Future[scalaz.\/-[Int]]) --- because --- argument expression's type is not compatible with formal parameter type; found : scala.concurrent.Future[scalaz.\/-[Int]] required: ?F[scalaz.\/[?A,?B]] lazy val et1:EitherT[Future, String, Int] = EitherT(Future(\/-(1))) ^Interim
@Interim It's because 1.right returns a \/ but \/-(1) returns a \/-. If you want to use the latter, give it an explicit type: \/-(1): \/[String, Int].Kitts
@Kitts Ah, thanks. I still haven't grokked subtyping + type classes.Interim
G
2

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)
Glebe answered 22/6, 2019 at 15:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.