0

I have a question about using Traverse together with EitherT. Let's say we have a code like this:

def validate(s: String): EitherT[Future, NumberFormatException, Int] = {
  EitherT(Future.successful(try { Right(s.toInt) } catch { case e: 
  NumberFormatException => Left(e)}))
}

List("1", "2").traverse(validate)

Unfortunately this code does not compile, because we are missing something:

error: could not find implicit value for evidence parameter of type cats.Applicative[G] List("1", "2").traverse(validate)

I tried to look this up and found for example this answer: Switching between EitherT and Validation to accumulate error or traverse or Validation versus disjunction

So it seems some solution could exists. But the problem is that both of them are using traverseU, which is no longer an option in scala 2.12. So how can this be done please?

EDIT This is the code including imports:

import cats.data.EitherT
import cats.syntax.traverse._
import cats.instances.list._
import cats.instances.future._
import scala.concurrent.ExecutionContext.global

import scala.concurrent.Future

def validate(s: String): EitherT[Future, NumberFormatException, Int] = {
  EitherT(Future.successful(try { Right(s.toInt) } catch { case e:
    NumberFormatException => Left(e)}))
}

List("1", "2").traverse(validate)
tomas.tunkl
  • 141
  • 1
  • 2
  • 10
  • Make sure that you have the compiler flag `-Ypartial-unification` set. To read more about why you need it: https://gist.github.com/djspiewak/7a81a395c461fd3a09a6941d4cd040f2 – Denis Rosca Aug 15 '18 at 19:32
  • @DenisRosca even with the flag doesn't work for me, and I would rather avoid it if I can. By new type definition it works for me. Thank you for help – tomas.tunkl Aug 17 '18 at 06:06
  • There is no need to avoid the `-Ypartial-unification` flag. "Add the flag" will probably be the first answer you get on any question related to FP programming in scala (be it cats/scalaz/whatever). It is meant to be the default behavior in 2.13.x anyway... – Denis Rosca Aug 17 '18 at 07:09

2 Answers2

2

Usually cats will pack specific evidence implicits under different imports. In this case, you need the proofs for List and Future.

  import cats.data.EitherT
  import cats.syntax.traverse._
  import cats.instances.list._
  import cats.instances.future._

  import scala.concurrent.Future

  def validate(s: String): EitherT[Future, NumberFormatException, Int] = {
    EitherT(Future.successful(try { Right(s.toInt) } catch { case e: NumberFormatException => Left(e) }))
  }

  List("1", "2").traverse(validate)

This code compiles with cats 1.2.0 for me.

flavian
  • 28,161
  • 11
  • 65
  • 105
  • Thanks for the reply. I have tried and still I got: error: no type parameters for method traverse: (f: String => G[B])(implicit evidence$1: cats.Applicative[G])G[List[B]] exist so that it can be applied to arguments (String => cats.data.EitherT[scala.concurrent.Future,NumberFormatException,Int]) – tomas.tunkl Aug 15 '18 at 06:57
  • @tomas.tunkl Not sure what you are doing different. I copy pasted what was compiling for me. Have you changed anything versus the example? Have you got other imports in scope that may be interfering? – flavian Aug 15 '18 at 09:23
  • I have updated question with imports I use. I am using cats 1.2.0. – tomas.tunkl Aug 15 '18 at 12:07
  • @tomas.tunkl This compiles well for me, your example. Remove the `ExecutionContext` import. – flavian Aug 16 '18 at 16:19
  • do you use the -Ypartial-unification flag? Which scala version you use? – tomas.tunkl Aug 17 '18 at 06:01
0
import cats.{Applicative, Monad}
import cats.data.EitherT
import cats.syntax.traverse._
import cats.instances.list._
import cats.instances.future._

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

def validate(s: String): EitherT[Future, NumberFormatException, Int] = {
    EitherT(Future.successful(try { Right(s.toInt) } catch { case e: NumberFormatException => Left(e) }))
  }

type Tmp[T] = EitherT[Future, NumberFormatException,T]
List("1", "2").traverse[Tmp, Int](validate)

So this is how it works to me. I had to create new type.

tomas.tunkl
  • 141
  • 1
  • 2
  • 10