preface

This article is about Cats, a basic type class: Show.

Level of learning: Complete mastery is required

At the beginning of 1.4 in Cats

In the previous section we learned how to implement a Type class in Scala. In this section we’ll learn about the type class already implemented in Cats.

The design of Cats is modular. We can freely choose the type class, instance and interface methods we want. Let’s look at our first example: cats.show.

The functionality of Show is basically the same as the Printable we implemented in the previous section. Its main function is a console that helps us export data in a friendlier way than the toString method. Here’s a simple declaration:

package cats
trait Show[A] {
  def show(value: A) :String
}
Copy the code

1.4.1 Importing Type Classes

Show type class declaration in cats package, we can directly import:

import cats.Show
Copy the code

In Cats, there is an apply method in the companion object of each type class to find instance of the corresponding type:

val showInt = Show.apply[Int]
// <console>:13: error: could not find implicit value for parameter
// instance: cats.Show[Int]
// val showInt = Show.apply[Int]
Copy the code

Implicit scope is an implicit scope that allows implicit scope to import the corresponding instance.

1.4.2 Importing the default Instances implementation

The cats.instances package provides a number of instances implemented by default. We can import them in the following way. Each type of package contains the instance implementation of that type for all type classes in Cats:

  • Cats.instances. Int Provides instances of all int instances
  • Cats.instances. String provides instances of all Stirng instances
  • List provides instances of all lists
  • Option Provides instances of all options
  • Cats. Instances. All provides all instances of cats

For more information about available imports, see the cats.Instances package.

Int instances Show instances Int instances Show instances

import cats.instances.int._    // for Show
import cats.instances.string._ // for Show

val showInt: Show[Int] = Show.apply[Int] 
val showString: Show[String] = Show.apply[String]
Copy the code

Now we can use them to print Int and String data:

val intAsString: String = showInt.show(123)
// intAsString: String = 123

val stringAsString: String = showString.show("abc")
// stringAsString: String = abc
Copy the code

1.4.3 Importing Interface Syntax

We can use interface syntax to make Show easier to use. First, we need to import cats.syntax. Show, which adds an extension to Show for any type provided that implicit Scope already has an instance of the corresponding type:

import cats.syntax.show._ // for show

val shownInt = 123.show
// shownInt: String = 123

val shownString = "abc".show
// shownString: String = abc
Copy the code

Cats provides syntax for each type class, which we can use on demand, and we will continue to cover them in later chapters.

1.4.4 Import All Content

In this book, we import on demand for each example, importing only the instances and syntax needed. However, sometimes this can be quite time-consuming, and you can simplify the import by:

  • Import cats._ Imports all type classes in cats
  • Import cats.instances. All._ Import all instances in cats
  • Import cats. Syntax. All._ Import all syntax from cats
  • Import cats. Implicits._ Import all instances and syntax from cats

Most of the time we just need to import them all:

import cats._
import cats.implicits._
Copy the code

But when it comes to naming conflicts or implicit conflicts, we need more specific imports.

1.4.5 Implementing a custom Instance

Instance = Show instance = Date instance = Show instance

import java.util.Date

implicit val dateShow: Show[Date] =
  new Show[Date] {
    def show(date: Date) :String =
      s"${date.getTime}ms since the epoch."
}
Copy the code

At the same time, Cats provides some cleaner ways to create instances. For Show, there are two methods in its companion object that help us create instances of a custom type:

object Show {
  
  // Convert a function to a `Show` instance:
  def show[A](f: A= >String) :Show[A] =???// Create a `Show` instance from a `toString` method:
  def fromToString[A] :Show[A] =??? }Copy the code

Using these methods is faster than the traditional way of creating an instance:

implicit val dateShow: Show[Date] = Show.show(date => s"${date.getTime}ms since the epoch.")
Copy the code

Cats provide a similar helper method for creating an instance for many type classes. You can create an instance directly from scratch, or you can create a new instance based on another type of instance, for example: Creates instance of type Option[Int] based on instance of type Int.

1.4.6 Exercise: Use Cat Show

Use Show type class to rewrite the Printable example in the previous section