En algún momento de su desarrollo el sujeto empieza a agrupar elementos que tienen características en común, tal vez ocurre en el instante mismo en que es enfrentado al orden de lo simbólico, al lenguaje: “La vaca hace muuu”. Este ejercicio de clasificación nos permite describir la realidad, así sabemos, por ejemplo, de los perros y los gatos; y los animales; y los vertebrados. Mas tarde, en alguna clase de matemáticas, se pintan figuritas entre círculos y se explican algunas reglas para realizar las asociaciones que usamos en nuestro lenguaje natural: de la intersección entre las plantas y los alimentos obtenemos las verduras (?).
Algunos lenguajes de programación tienen un tipo de dato compuesto muy versátil que permite crear nuevos tipos combinando otros. Cuando hablamos de estos tipos nos referimos, así como en los conjuntos, a todos los posibles elementos que agrupamos bajo una etiqueta. Los tipos pueden ser combinados con otros haciendo uso de las operaciones de unión y producto cartesiano, así nos encontramos con los union types y los product types respectivamente.
La unión establece que “Un elemento x pertenece a la unión de los conjuntos A y B si, y sólo si, x pertenece al conjunto A o (∨) x pertenece al conjunto B”. Para crear tipos usando la operación de unión, es decir, los union types, cambiaremos el O por el símbolo |, al menos en haskell y f#. Tomemos el ejemplo que encontramos en la wikipedia: La unión de personas que juegan al fútbol y de personas que juegan al baloncesto serían las personas que juegan a fútbol o baloncesto.
data JueganFutbolOBaloncesto = Futbol Persona | Baloncesto Persona
Los conjuntos de las personas que juegan fútbol y el de los que juegan baloncesto son representados con los constructores (data constructor) Fútbol y Baloncesto respectivamente, estos no son nuevos tipos por lo que no podemos hacer algo como
foo :: Futbol -> String
En su lugar usamos el pattern matching para saber si un elemento pertenece al constructor fútbol o baloncesto.
foo :: JueganFutbolOBaloncesto -> String foo Futbol p = nombre p foo Baloncesto p = nombre p
En la misma pagina dice “El producto cartesiano de dos conjuntos A y B es el conjunto C, C = A × B, donde los pares ordenados (a,b) están formados por un primer elemento perteneciente a A y (∧) un segundo elemento perteneciente a B”. Los tipos que se crean usando la operación de producto, es decir, los product types, contienen los elementos ordenados (n-tupla) de la combinación de los conjuntos operando. Veamos, de nuevo, el ejemplo de la wikipedia: “El producto cartesiano de A={2,3} y B={a,b,c} es A×B={(2,a),(2,b),(2,c),(3,a),(3,b),(3,c)}”
type C = (Int,Char)
El tipo C = Int x Char. Podemos entonces definir un nuevo tipo Persona que contiene todos los valores del tipo Nombre y todos los valores del tipo Apellido
type Persona = (Nombre,Apellido)
También es posible definir “nombres” para los elementos de una tupla, estos los conocemos como records.
data Persona = Persona { nombre :: Nombre , apellido :: Apellido }
Podemos combinar los union types y los product types para expresar casos como, por ejemplo: Una persona tiene un nombre y un apellido y un peso en libras o en kilogramos. Los y los representamos con tuplas o con records y los o con el union type
data Peso = Lb Int | Kg Int data Persona = Persona { nombre :: String , apellido :: String , peso :: Peso }
y su uso
pepito = Persona {nombre="Pepito", apellido="Perez", peso= Kg 80}
Tener claro de donde vienen estos tipos de datos nos ayuda a entender no solo de donde viene ese extraño nombre sino que puede resultar útil en el momento de razonar sobre los tipos que creamos para modelar soluciones.
Hasta el próximo post.