Translate

jueves, 17 de febrero de 2022

Type class en Scala parte 2


Seguimos con Type class en Scala

Un uso de clase de tipo es cualquier funcionalidad que requiere una instancia de clase de tipo para funcionar. En Scala esto significa cualquier método que acepte instancias de la clase de tipo como parámetros implícitos.

La forma más sencilla de crear una interfaz que utilice una clase de tipo es colocar métodos en un objeto único:

object Json {

  def toJson[A](value: A)(implicit w: JsonWriter[A]): Json =

    w.write(value)

}

Para usar este objeto, importamos cualquier instancia de clase de tipo que nos interese y llamamos al método relevante:

import JsonWriterInstances._
Json.toJson(Person("Dave", "dave@example.com"))
// res1: Json = JsObject(
// Map("name" -> JsString("Dave"), "email" -> JsString("dave@example.com"))
// )

El compilador detecta que hemos llamado al método toJson sin proporcionar los parámetros implícitos. Intenta arreglar esto buscando instancias de clase de tipo de los tipos relevantes e insertándolos en el sitio de la llamada:

Json.toJson(Person("Dave", "dave@example.com"))(personWriter)

Alternativamente, podemos usar métodos de extensión para extender los tipos existentes con métodos de interfaz. 

object JsonSyntax {
  implicit class JsonWriterOps[A](value: A) {
    def toJson(implicit w: JsonWriter[A]): Json =
      w.write(value)
  }
}

Usamos la sintaxis de la interfaz importándola junto con las instancias para los tipos que necesitamos:

import JsonWriterInstances._

import JsonSyntax._

Person("Dave", "dave@example.com").toJson

// res3: Json = JsObject(

// Map("name" -> JsString("Dave"), "email" -> JsString("dave@example.com"))

// )

Nuevamente, el compilador busca candidatos para los parámetros implícitos y los completa por nosotros:

Person("Dave", "dave@example.com").toJson(personWriter)

La biblioteca estándar de Scala proporciona una interfaz de clase de tipo genérico llamada implicitly. Su definición es muy sencilla:

def implicitly[A](implicit value: A): A = value

Podemos usar implicitly para invocar cualquier valor del alcance implícito. Proporcionamos el tipo que queremos e implícitamente hace el resto:

import JsonWriterInstances._

implicitly[JsonWriter[String]]
// res5: JsonWriter[String] = repl.

Podemos usar implicitly para invocar cualquier valor del alcance implícito. Proporcionamos el tipo que queremos e implícitamente hace el resto:

import JsonWriterInstances._
implicitly[JsonWriter[String]]
// res5: JsonWriter[String] = repl.

Podemos insertar una llamada a implícitamente dentro del flujo general de nuestro código para garantizar que el compilador pueda encontrar una instancia de una clase de tipo y asegurarse de que no haya errores implícitos ambiguos.