Missing cats instance

I have this code whereby process is having problem compiling with error “Could not find an instance of Applicative”. I know i can import all cats implicits but i wish to learn exactly which instance is missing. Can someone point it out to me?

object Cats extends App {
  import cats.syntax.apply._
  import cats.syntax.applicative._
  import cats.Applicative

  def listSequence[F[_]: Applicative, B](list: List[F[B]]): F[List[B]] =
    listTraverse(list)(identity)

  def listTraverse[F[_]: Applicative, A, B](
      list: List[A]
  )(func: A => F[B]): F[List[B]] =
    list.foldLeft(List.empty[B].pure[F]) { (accum, item) =>
      (accum, func(item)).mapN(_ :+ _)
    }

  import cats.syntax.validated._
  import cats.data.Validated

  type ErrorOr[A] = Validated[String, A]

  def process(inputs: List[Int]): ErrorOr[List[Int]] =
    listTraverse(inputs) { n =>
      if (n % 2 == 0) n.valid
      else s"$n is odd".invalid
    }
}

It would help us to pinpoint the problem if you post the exact error message you get and also say which line it refers to in your program.

1 Like

But, squinting over your code, it seems you are missing the type class instances for List:

import cats.instances.list._

I simplified the code to this

object Cats extends App {
  import cats.data.Validated
  import cats.instances.list._
  import cats.syntax.traverse._

  List(1, 2, 3).traverse(item =>
    if (item % 2 == 0) Validated.valid(item)
    else Validated.invalid(s"$item is not even")
  )

}

The error:

[error] /Users/laiboonhui/learn/cats/hello/src/main/scala/Hello.scala:8:25: Could not find an instance of Applicative for [+A]cats.data.Validated[String,A]
[error] List(1, 2, 3).traverse(item =>
[error] ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed

I wonder what instance of Applicative i am missing. Its not list

You’re still missing import cats.instances.string._.
Validated is Applicative only if its error is a Semigroup.

2 Likes

OMG why didnt i think of that. Thank you for pointing out. Looks like i do not understand the Validated type class enough

I highly recommend you just do import cats.implicits._ to get everything, and not import things from cats.instances or cats.syntax. It’s very easy to import insufficient and/or conflicting things.

2 Likes

I would just use ValidatedNec which will give you the Semigroup automatically.

List(1, 2, 3).traverse { item =>
  if (item % 2 == 0) Validated.validNec(item)
  else Validated.invalidNec(s"$item is not even")
}

Remember that:

ValidatedNec[E, A] = Validated[NonEmptyChain[E], A]

Another three good reasons for using ValidatedNec are:

  1. Usually, if you want multiple errors, you want a collection of them, not a big error.
  2. It ensures that if there are errors, there is at least one.
  3. Concatenating and traversing a Chain is cheap.
1 Like

That sums up nicely the problem with Scala’s implicits.