Before we start talking about the Functional Programming with the Scala Cats, we should refresh our memory about the Type Class and Implicit. These are the base when we start learning the Scala Cats.
Let’s start the discussion with the Type Class.
Type Class
A type class is an interface or API that represents some functionality, which we want to implement. Type class is programming pattern in Haskell which allows us to extend existing libraries with new functionality. In Cats, a type class is represented by a trait with at least one type parameter.(If you don’t know about the trait or want to refresh look here: Back2Basics: The Story of Trait – Part 1)
Now we will see, how can we implement Type Class with traits:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sealed trait Json | |
final case class JsObject(get: Map[String, Json]) extends Json | |
final case class JsString(get: String) extends Json | |
final case class JsNumber(get: Double) extends Json | |
case object JsNull extends Json | |
trait JsonWriter[A] { | |
def write(value: A): Json | |
} |
Here as we can see that JsonWriter is a Type class with the Json which provides the support for the rest operations.
Now we will discuss the Type Class Instances because it provides the implementation for the types. Now in Scala, we create the instance with the help of concrete implementation and implicit. Example:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
final case class Person(name: String, email: String) | |
object JsonWriterInstances { | |
implicit val stringWriter: JsonWriter[String] = | |
new JsonWriter[String] { | |
def write(value: String): Json = JsString(value) | |
} | |
implicit val personWriter: JsonWriter[Person] = | |
new JsonWriter[Person] { | |
def write(value: Person): Json = | |
JsObject(Map( | |
"name" –> JsString(value.name), | |
"email" –> JsString(value.email) | |
)) | |
} | |
} |
Now we will create a Type Class Interface, which will expose the functionality to the users. Interface use the generic method that will take the instance of the type class as an implicit parameter. We can access interface in two way:
- Interface Object
- Interface Syntax
Interface Object: Now we can create an interface. It will place a method into a singleton object:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object Json { | |
def toJson[A](value: A)(implicit w: JsonWriter[A]): Json = w.write(value) | |
} |
Now we can call it like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import JsonWriterInstances._ | |
Json.toJson(Person("Dave", "dave@example.com")) | |
//res1: Json = JsObject(Map(name -> JsString(Dave), email -> JsString(dave@example.com))) |
Here we can see that we haven’t provided the implicit parameter but we are calling the toJson method. Now compiler will search for the type class instance and provide it to the call like:
Interface Syntax: We can use extension methods also for extending the existing type with the interface.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object JsonSyntax { | |
implicit class JsonWriterOps[A](value: A) { | |
def toJson(implicit w: JsonWriter[A]): Json = | |
w.write(value) | |
} | |
} |
Now we can use it, like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import JsonWriterInstances._ | |
import JsonSyntax._ | |
Person("Dave", "dave@example.com").toJson | |
// res6: Json = JsObject(Map(name -> JsString(Dave), email -> JsString(dave@example.com))) |
Again we can see that we haven’t provided the implicit parameter but we are calling the toJson method. Now compiler will search for the type class instance and provide it to the call like:
So we have discussed till now for the Type Class. In our next blog, we will talk about the Implicit and Scala Cat Structure.
Reference:
Reblogged this on Anurag Srivastava.
Reblogged this on Harmeet Singh(Taara).
Reblogged this on Agile Development .