Tipos compuestos I Algoritmos y Estructuras de Datos I cada valor de un tipo básico representa un elemento atómico e indivisible I I I Segundo cuatrimestre de 2015 I I Departamento de Computación - FCEyN - UBA I Clases teóricas - clase 4 un valor de un tipo compuesto contiene información que puede ser dividida en componentes de otros tipos ya vimos dos ejemplos de tipos compuestos: I Especificación de Tipos compuestos I I Int Float Bool Char secuencias tuplas para definir un tipo compuesto, tenemos que darle I I I un nombre uno o más observadores condiciones invariantes 1 Observadores I 2 Observadores funciones que se aplican a valores del tipo compuesto y devuelven el valor de sus componentes (pueden tener más parámetros) I los observadores definen el tipo compuesto I I I Ejemplo: Tipo Punto I I I I sus elementos representan puntos en el plano componentes: coordenadas (x e y ) un observador para obtener cada una I los observadores pueden tener precondiciones I Definición: tipo Punto { observador X (p : Punto) : Float; observador Y (p : Punto) : Float } 3 si dos términos del tipo dan el mismo resultado para todos los observadores, entonces se los considera iguales esta condición define la igualdad == para tipos compuestos (el operador == existe en todos los tipos) si vale la precondición, no pueden devolver un valor indefinido I los observadores no tienen poscondiciones propias I si hay condiciones generales que deben cumplir los elementos del tipo, se las presenta como invariantes de tipo 4 Más sobre el tipo Punto I Tipo Cı́rculo Ejemplo: Especificación de un problema que recibe dos números reales y construye un punto con esas coordenadas: problema nuevoPunto(a, b : Float) = res : Punto { asegura X (res) == a; asegura Y (res) == b; } I Cuando el resultado es de un tipo compuesto, usamos los observadores para describir el resultado I Ejemplo: Función auxiliar para calcular la distancia entre dos puntos aux dist(p, q : Punto) : Float = (X (p) − X (q))2 + (Y (p) − Y (q))2 Sus elementos representan cı́rculos en el plano, formados por un Punto que es su centro, y un real positivo que es su radio. 1/2 6 5 Tipo Cı́rculo Invariantes de tipo Un invariante de tipo es una expresión booleana que relaciona los observadores del tipo, y es verdadera para cada elemento del tipo. I sus componentes son de tipos distintos Un invariante de tipo I Da condiciones que deben cumplir todos los elementos de un tipo compuesto. I Al especificar un tipo damos explı́citamente los invariantes de tipo. I Al observar un elemento de un tipo compuesto está garantizado que se cumplen los invariantes. I Al construir un elemento de un tipo compuesto tendremos que asegurar que se cumplan los invariantes. tipo Cı́rculo { observador Centro(c : Cı́rculo) : Punto; observador Radio(c : Cı́rculo) : Float; invariante Radio(c) > 0; } I el invariante del tipo especifica las condiciones que deben cumplir entre sı́ los valores obtenidos por los observadores para cualquier elemento del tipo I es la garantı́a de que los elementos estarán bien construidos tipo T { observador . . . ; .. . invariante R(x); } 7 8 Invariantes de tipo I Tipo Cı́rculo los problemas que reciben valores del tipo compuesto como argumentos pueden suponer que se cumplen los invariantes I Ejemplo: Especificar el problema de construir un cı́rculo a partir de su centro y su radio: problema nuevoCı́rculo(c : Punto, r : Float) = res : Cı́rculo { requiere r > 0; asegura (Centro(res) == c ∧ Radio(res) == r ); tipo T { observador . . . ; .. . } invariante R(x); } I problema probA(. . . , x : T, . . . ) = . . . { requiere . . . ∧ R(x) ∧ . . . ; | {z } Ejemplo: Especificar el problema de construir un cı́rculo a partir de su centro y un punto sobre la circunferencia: problema nuevoCı́rculoPuntos(c, x : Punto) = res : Cı́rculo { requiere dist(c, x) > 0; asegura (Centro(res) == c ∧ Radio(res) == dist(c, x)); no hace falta asegura . . . ; } } 9 10 Tipo MatrizhT i Tipos genéricos I I I en los ejemplos vistos, cada componente es de un tipo determinado de antemano I I su contenido van a ser valores no siempre del mismo tipo comportamiento uniforme se llaman tipos genéricos o tipos paramétricos I I tipo MatrizhT i { observador filas(m : MatrizhT i) : Int; observador columnas(m : MatrizhT i) : Int; observador val(m : MatrizhT i, f , c : Int): T { requiere 0 ≤ f < filas(m); requiere 0 ≤ c < columnas(m); precondición del observador } invariante filas(m) > 0; invariante columnas(m) > 0; } también hay tipos compuestos que representan una estructura I tipo genérico de las matrices cuyos elementos pertenecen a un tipo cualquiera T definen una familia de tipos, y cada elemento de la familia es una instancia del tipo genérico los problemas que usen un tipo genérico definen una familia de problemas I 11 ejemplo: una instancia del tipo genérico MatrizhT i es MatrizhChari 12 Operaciones genéricas con matrices I Operaciones sobre matrices para tipos instanciados I expresión que cuenta la cantidad de elementos de una matriz aux suma(m : MatrizhInti) : Int = P [val(m, i, j) | i ← [0..filas(m)), j ← [0..columnas(m))]; aux elementos(m : MatrizhT i) : Int = filas(m) ∗ columnas(m); I expresión que suma los elementos de una matriz de enteros especificación del problema de cambiar el valor de una posición de una matriz I problema cambiar(m : MatrizhT i, f , c : Int, v : T ) { requiere 0 ≤ f < filas(m); requiere 0 ≤ c < columnas(m); modifica m; asegura filas(m) == filas(pre(m)); asegura columnas(m) == columnas(pre(m)); asegura val(m, f , c) == v ; asegura (∀i ← [0..filas(m))) asegura (∀j ← [0..columnas(m)), ¬(i == f ∧ j == c)) asegura val(m, i, j) == val(pre(m), i, j))); } especificación del problema de construir la matriz identidad de n × n: problema matId(n : Int) = ident : MatrizhInti { requiere n > 0; asegura filas(ident) == columnas(ident) == n; asegura (∀i ← [0..n)) val(ident, i, i) == 1; asegura (∀i ← [0..n))(∀j ← [0..n), i 6= j) val(ident, i, j) == 0; } I I I ¿importa el orden? sı́; si estuviera al revés, se podrı́a indefinir val(ident, i, i) en este caso, se indefinirı́a la poscondición, valiendo la precondición 14 13 El tipo SecuenciahT i Tuplas I I ya lo usamos con su nombre alternativo: [T ] I presentamos también sus observadores: longitud e indexación tipo ParhA, Bi{ observador primero(p : Par hA, Bi) : A observador segundi(p : Par hA, Bi) : B } tipo SecuenciahT i { observador long (s : SecuenciahT i) : Int; observador ı́ndice(s : SecuenciahT i, i : Int) : T { requiere 0 ≤ i < long (s); −→ precondición de observador } invariante long(s) ≥ 0; } I tipo TernahA, B, C i{ observador primero(p : TernahA, B, C i) : A observador segundo(p : TernahA, B, C i) : B observador tercero(p : TernahA, B, C i) : C } notaciones alternativas I I secuencias de longitud fijo, en las que cada elemento puede pertenecer a un tipo distinto (predeterminado de antemano) |s| para la longitud si o s[i] para la indexación I Notación: 1. ParhA, Bi también se puede escribir (A, B) 2. TernahA, B, C i también se puede escribir (A, B, C ) 15 16