Un vistazo a los conceptos de tipos en Scala

Liván Frómeta
4 min readAug 25, 2022
Photo by Glen Carrie on Unsplash

Introducción

Cuando comencé a aprender el hermoso language programación, Scala, escuchaba muchos concepts sobre los tipos en Scala que al principio llegan a abrumarte, crees que son imposible o complicados de aprender y en un principio puede que así sea pero la idea es irlos incorporando en tu vocabulario, compartirlos con tus compañeros en fin utilizarlos cuando te sean necesarios. Mi objetivo con este post es facilitar el entendimiento de estos conceptos sobre los tipos en Scala pero primero debemos responder una pregunta básica y entender que es un valor en Scala.

Qué es un valor?

Los valores son el concepto más simple con el que debemos tratar. Tienen el nivel más bajo de abstracción dentro de los conceptos sobre tipos en Scala, en fin son valores simples sin procesar.

val banana : String      = "🍌" 
val fruitCount: Int = 2
val fruits: List[String] = List("🍌 Banana", "🥭 Mango")
val favoriteFor = Map("juice"-> "🍍 Pineapple")

Mira el lado derecho de estos ejemplos, son todos valores.

Conceptos principales

Tipos propios

Son tipos que se pueden asignar a un valor por sí mismos, aquí podemos encontrar los tipos nativos básicos como pueden ser: Int, Float, Double y String por nombrar algunos.

Los tipos propios son un concepto de más alto nivel que los valores. Los tipos propios se pueden instanciar para producir un valor y los valores son una instancia específica de un tipo.

val banana : String      = "🍌" 
val fruitCount: Int = 2 val bananaPrice: Double = 1.80d
val fruits: List[String] = List("🍌 Banana", "🥭 Mango")
val favoriteFor = Map("juice"-> "🍍 Pineapple")

Los tipos propios son conocidos en inglés como proper types o level zero o zero-order types. Pasar de los valores a los tipos propios nos lleva al siguiente nivel de abstracción.

Tipos de primer orden

En el ejemplo anterior puedes ver que List[String] es un tipo propio, pero ¿qué es List , Option , Either o Map? Los tipos de primer orden toman como parámetro otro tipo por lo que no pueden ser adjuntado a un valor ya que dependen de otro tipo para su creación como podemos ver en el siguiente ejemplo.

scala> val fruits: List = List("🍌 Banana", "🥭 Mango")                                         
^
error: type List takes type parameter

Este error de compilación se debe a que Scala no permite usar List como un tipo, necesitamos que lo declaremos como List[_]. Es decir, para obtener una instancia de un tipo de primer orden necesitamos pasar al tipo List un tipo propio. Por esta razón, el ejemplo anterior quedaría como:

val fruits: List[String] = List("🍌 Banana", "🥭 Mango")

En el caso del tipo Map es muy parecido pero en lugar de necesitar un parámetro necesita dos, uno para la clave y otro para el valor, sería algo como Map[_,_] — e.g Map[Int, String]. Los tipos de primer orden son conocidos en inglés como first-order o level one types.

Constructores de tipo

Un constructor de tipo, definidos como [_] , es una función que toma un tipo y devuelve un tipo — por ejemplo un constructor de tipo para List[_] tendríamos la siguiente definición.

T => List[T] // String => List[String]

En conclusión es una función que dado un tipo propio, devolverá otro tipo propio como puede ser (Int) => Int . Los constructores de tipos son conocidos en inglés como type constructor, comento esta terminología en inglés porque son los nombres que encontrarás en todos los libros que hablas sobre este tema.

Tipos de segundo orden

Cada tipo mencionado hasta ahora corresponde a un nivel de abstracción, ahora que pasa cuando creamos un tipo que toma como parámetro un tipo de primer order.

List("🍍 Pineapple") -> List[String] -> List -> ??? 
// ↑ ↑ ↑
// valor tipo propio tipo de primer orden

El resultado es conocidos en inglés como higher kinded o second-order types, se define en Scala de la siguiente forma:

trait Functor[F[_]] {    
def map[A, B](fa: F[A])(f: A => B): F[B]
}

Si has llegado hasta aquí has podido ver como van encajando todas los conceptos sobre tipos en Scala.

Recapitulando

  • Valores: Parte derecha de la asignación como es "🍌", 1 , List("🍌")
  • Tipos propios: Int, Float, Double, String
  • Tipos de primer orden: List , Option , Either , Map
  • Constructores de tipo: [_]
  • Tipos de orden superior: Functor[F[_]] , G[F[_]]

Comentado esto, pasaremos ha hacer una última definición basada en los niveles de tipos antes mencionados y representado su nivel de abstracción. Es muy común encontrar estos símbolos para representar los niveles de tipos de Scala en varias bibliografías y por eso es importante comentarlos a continuación como punto final para concluir el post.

Niveles de tipos

Los niveles de tipos (type level) son la definición de un tipo de un tipo, también se le llama clase y se usa * como notación para comunicar en qué orden se encuentran.

  • * — e.g String. Representan tipos propios(zero-order)
  • * -> * — e.g List[_]. Representan tipos de primer orden(first-order) que requieren un parámetro
  • * -> * -> * — e.g Map[_,_]. Representan tipos de primer orden(first-order) que requieren dos parámetro
  • (* -> *) -> * — e.g G[F[_]]. Representan tipos de segundo orden (higher kinded o second-order )

Después de esta breve explicación pero cargada de mucho contenido espero haber aclarado algunas dudas referente a los conceptos de tipos en Scala. Como comenté al principio, inclúyelos en tu vocabulario y comparte este post con tus compañeros para ayudar a propagar el conocimiento sobre los conceptos de tipos en Scala.

Referencias

--

--

Liván Frómeta

Functional Programming enthusiast, proficient in Scala & Principal Software Engineer at @auctane