Cats: how to find the specific type from implicits

716 views Asked by At

I have this code which compiles and works fine

import cats.implicits._
Cartesian[ValidResponse].product(
    getName(map).toValidated,
    readAge(map).toValidated
).map(User.tupled)

However I don't like the import of cats.implicits._ because there is just too many classes there. I tried importing specific things related to Cartesians like

import cats.implicits.catsSyntaxCartesian
import cats.implicits.catsSyntaxUCartesian
import cats.implicits.catsSyntaxTuple2Cartesian

But these did not work. As a newbie I find the implicit imports very confusing because there are simply 1000s of them and the names are not very obvious. My only alternative is to import the entire universe by import cats.implicits._ and stop thinking about it.

In fact I have a broader confusion about cats.implicits, cats.instances._ and cats.syntax._. So far I am just importing these via trial and error. I am not really sure of when to import what.

2

There are 2 answers

0
HTNW On BEST ANSWER

Do not try to pick out specific things from cats.implicits. You either import the entire thing, or you don't use it at all. Further, there's no reason to be afraid of importing it all. It can't interfere with anything.

Ok, I lied. It will interfere if you import cats.instances.<x>._ and/or cats.syntax.<x>._ alongside cats.implicits._. These groups are meant to be mutually exclusive: you either import everything and forget about it with cats.implicits._, or you specifically select what you want to import with cats.instances and cats.syntax.

These two packages are not meant to be imported completely like cats.implicits. Instead, they include a bunch of objects. Each object contains some implicit instances/syntax, and you are meant to import from those.

import cats.implicits._ // Good, nothing to fear
// RESET IMPORTS
import cats.implicits.catsSyntaxCartesian // Bad, don't pick and choose
// RESET IMPORTS
import cats.instances._ // Bad, is useless
import cats.syntax._    // Ditto
// RESET IMPORTS
import cats.instances.list._   // ok
import cats.syntax.cartesian._ // ok
// RESET IMPORTS
import cats.implicits._
import cats.syntax.monad._ // Bad, don't mix these two

Additionally each of cats.{ instances, syntax } contains an all object, with the obvious function. The import cats.implicits._ is really a shortcut for import cats.syntax.all._, cats.instances.all._.

0
Denis Rosca On

I'll start by saying that import cats.implicits._ is safe, reasonable and the recommended approach when starting. So if the only reason for this question is that you don't like importing too many classes, then I think you should just bite the bulled at leave that as is.

Additionally, I recommend you take a look at the official cats import guide. It tries to explain the package/logical structure of cats code and might make it easier to understand.

The "cats" library is organized in several "areas" that can be easily distinguished by their package name:

  1. cats._ - This is where most of the typeclasses live (e.g. Monad, Foldable etc.)
  2. cats.data._ - This is the home of data structures like Validated and State.
  3. cats.instances._ - This is where the instances for the typeclasses defined in 1 are. For example if you import cats.instances.list._ you'll bring into scope the Show, Monad etc. instances for the standard List. This is what you're most likely interested in.
  4. cats.syntax._ - has some syntax enrichment that makes code easier to write and read.

An example of ussing cats.syntax._ would be:

import cats.Applicative
import cats.syntax.applicative._

val listOfInt = 5.pure[List]
//instead of 
val otherList = Applicative[List[Int]].pure(5)