David Przybilla David Przybilla - 2 months ago 26
Scala Question

Scala with Cats - Cartesian + Validated

I'm doing a simple exercise from the book

Advanced scala with cats
on my own.

I want to use
Cartesian
with
Validated
.

/*
this works
*/
type ValidatedString = Validated[ Vector[String], String]
Cartesian[ValidatedString].product(
"a".valid[Vector[String]],
"b".valid[Vector[String]]
)





/* this doesnt work*/
type Result[A] = Validated[List[String], A]
Cartesian[ValidatedString].product(
f(somevariable)//returns Result[String],
g(somevariable)//returns Result[Int],
).map(User.tupled) // creates an user from the returned string, int


Im completely clueless. Any hints ?
Im getting :


could not find implicit value for parameter instance: cats.Cartesian[Result]
Cartesian[Result].product(
^

Answer

Without seeing your imports I'd guess the issue is that you're missing a Semigroup instance for List (or Vector—it's not clear which you want to use), since the following works for me:

import cats.Cartesian, cats.data.Validated, cats.implicits._

type Result[A] = Validated[List[String], A]

Cartesian[Result].product(
  "a".valid[List[String]],
  "a".valid[List[String]]
)

You could replace the cats.implicits._ part with the following:

import cats.instances.list._
import cats.syntax.validated._

…but I'd suggest starting with cats.implicits._.

The problem here is that Validated accumulates failures when you combine two instances with product, and what "accumulates" means in a particular context is determined by a Semigroup instance for the invalid type that tells you how to "add" two invalid values together.

In the case of List (or Vector), concatenation makes sense for this accumulation operation, and Cats provides the concatenation Semigroup for any List[A], but in order to get it to be applied here you have to explicitly import it (either from cats.implicits or from cats.instances.list).