El patrón Type Class
Polimorfismo ad hoc
El patrón Type Class es una lección gratuita de Scala for Backend Engineering & Functional Programming en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Scala for Backend Engineering & Functional Programming, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Scala for Backend Engineering & Functional Programming incluye 4 lecciones en total.
¿Qué es una clase de tipos?
Una clase de tipos es un patrón para añadir comportamiento a tipos sin modificarlos. Es una forma de polimorfismo ad hoc: una misma operación funciona con muchos tipos no relacionados, y el compilador la elige según el tipo.
Este concepto procede de Haskell y se usa ampliamente en bibliotecas de Scala como Cats.
El problema que resuelve
La herencia incorpora el comportamiento a un tipo en el momento de su definición. Sin embargo, a menudo no puede editar un tipo (porque pertenece a una biblioteca) o desea comportamientos diferentes en distintos contextos. Las clases de tipos le permiten asociar el comportamiento externamente.
Paso 1: definir el trait
Una clase de tipos es un trait parametrizado por un tipo. Aquí, Show[A] describe cómo representar cualquier A como un String.
trait Show[A] {
def show(value: A): String
}
@main def run(): Unit = {
println("Show trait defined")
}Paso 2: Proporcionar instancias
Para cada tipo concreto que desee admitir, cree una instance del trait. Estas son las instancias de la clase de tipos.
trait Show[A] { def show(value: A): String }
object Main {
val intShow: Show[Int] = (v: Int) => s"Int($v)"
val strShow: Show[String] = (v: String) => s"Str($v)"
def main(args: Array[String]): Unit = {
println(intShow.show(7))
println(strShow.show("hi"))
}
}Paso 3: Usar la instancia
Una función recibe la instancia como parámetro. La misma función render funciona con cualquier tipo que tenga una instancia de Show.
trait Show[A] { def show(value: A): String }
object Main {
def render[A](value: A, s: Show[A]): String = s.show(value)
val intShow: Show[Int] = (v: Int) => s"<$v>"
def main(args: Array[String]): Unit = {
println(render(99, intShow))
}
}Hacerlo implícito
Pasar las instancias manualmente resulta tedioso. Marcar la instancia como implicit y el parámetro como implicit (o using en Scala 3) permite que el compilador la proporcione automáticamente.
trait Show[A] { def show(value: A): String }
object Main {
implicit val intShow: Show[Int] = (v: Int) => s"<$v>"
def render[A](value: A)(implicit s: Show[A]): String = s.show(value)
def main(args: Array[String]): Unit = {
println(render(42))
}
}Polimorfismo ad hoc
El mismo nombre de función se dirige a distintas implementaciones según el tipo del argumento. Este es el polimorfismo ad hoc, distinto del polimorfismo por subtipos (herencia) y del polimorfismo paramétrico (genéricos).
trait Show[A] { def show(value: A): String }
object Main {
implicit val intShow: Show[Int] = (v: Int) => s"int:$v"
implicit val boolShow: Show[Boolean] = (v: Boolean) => s"bool:$v"
def render[A](value: A)(implicit s: Show[A]): String = s.show(value)
def main(args: Array[String]): Unit = {
println(render(5))
println(render(true))
}
}Trabajar con tipos personalizados
La verdadera ventaja es añadir comportamiento a sus propios tipos de forma limpia, manteniendo la clase de datos libre de responsabilidades de formato.
trait Show[A] { def show(value: A): String }
case class User(name: String, age: Int)
object Main {
implicit val userShow: Show[User] = (u: User) => s"${u.name} (${u.age})"
def render[A](value: A)(implicit s: Show[A]): String = s.show(value)
def main(args: Array[String]): Unit = {
println(render(User("Ada", 36)))
}
}Clases de tipos frente a interfaces
Una interfaz vincula el comportamiento a la definición del tipo; una clase de tipos los desacopla.
- Puede añadir una instancia de una clase de tipos a un tipo que no le pertenece.
- Puede tener varias instancias para distintos contextos.
- El compilador selecciona el comportamiento en el punto de llamada.
Tres componentes
Toda clase de tipos tiene tres partes:
- El trait (la operación abstracta).
- Las instancias (las implementaciones para cada tipo).
- La interfaz (las funciones que requieren una instancia).
Explorará cada una en las lecciones siguientes.
Un miniejemplo completo
Integraremos el patrón mediante una función genérica que utiliza una instancia implícita.
trait Show[A] { def show(value: A): String }
object Main {
implicit val intShow: Show[Int] = (v: Int) => s"#$v"
implicit val strShow: Show[String] = (v: String) => '"' + v + '"'
def printAll[A](xs: List[A])(implicit s: Show[A]): Unit =
xs.foreach(x => println(s.show(x)))
def main(args: Array[String]): Unit = {
printAll(List(1, 2, 3))
printAll(List("a", "b"))
}
}Comprobación rápida
Compruebe cuánto domina el patrón de clases de tipos.
Resumen
Ha aprendido el patrón de clases de tipos:
- Un
traitparametrizado describe una operación. - Las instancias la implementan para cada tipo.
- Los parámetros
implicitpermiten que el compilador proporcione la instancia. - Esto proporciona polimorfismo ad hoc y permite ampliar tipos que no le pertenecen.
Preguntas frecuentes
¿La lección «El patrón Type Class» es gratis?
Sí — el texto completo de «El patrón Type Class» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Scala for Backend Engineering & Functional Programming, actualiza a CoddyKit PRO. El curso de Scala for Backend Engineering & Functional Programming incluye 4 lecciones en total.
¿Qué aprenderé en «El patrón Type Class»?
Polimorfismo ad hoc Practicas Scala for Backend Engineering & Functional Programming con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Scala for Backend Engineering & Functional Programming?
No se requiere experiencia previa. Scala for Backend Engineering & Functional Programming en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.
¿Cuánto tiempo toma la lección «El patrón Type Class»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Scala for Backend Engineering & Functional Programming?
Sí. Cada lección de Scala for Backend Engineering & Functional Programming incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- El patrón Type Class
- Definición de instancias
- Type Classes comunes
- Derivación de Type Classes