Algoritmos y Estructuras de Datos I Tipos compuestos Observadores

Anuncio
Tipos compuestos
I
cada valor de un tipo básico representa un elemento atómico,
indivisible
I
Algoritmos y Estructuras de Datos I
I
I
I
Primer cuatrimestre 2007
I
I
Teórica de especificación 4
Tipos compuestos
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
I
I
Int
Float
Bool
Char
secuencias: un valor de tipo secuencia de enteros tiene varios
componentes, cada uno es un entero
tuplas: un valor de tipo par ordenado de enteros tiene dos
componentes
para definir un tipo compuesto, tenemos que darle
I
I
un nombre
uno o más observadores
1
Observadores
2
Tipo Punto
I
I
funciones que se aplican a valores del tipo compuesto y
devuelven el valor de sus componentes
I
I
I
I
si dos términos del tipo dan el mismo resultado para todos los
observadores, se los considera iguales
esta es la definición implı́cita de la igualdad == para tipos
compuestos (el == está en todos los tipos)
I
pueden tener precondiciones
I
no tienen poscondiciones propias
I
si hay condiciones generales que deben cumplir los elementos
del tipo, se las presenta como invariantes de tipo
especificación una función 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;
}
si vale la precondición, no pueden devolver un valor indefinido
I
un punto en el plano
componentes: coordenadas (x e y )
un observador para obtener cada una
tipo Punto {
observador X (p : Punto) : Float;
observador Y (p : Punto) : Float
}
pueden tener más parámetros
definen el tipo compuesto
I
I
I
I
Cuando el resultado es de un tipo compuesto, usamos los
observadores para describir el resultado
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
3
1/2
4
Tipo Cı́rculo
I
Invariantes de tipo
sus componentes son de tipos distintos
tipo Cı́rculo {
observador Centro(c : Cı́rculo) : Punto;
observador Radio(c : Cı́rculo) : Float;
invariante Radio(c) > 0;
}
I
I
son la garantı́a de que los elementos estén bien construidos
I
deben cumplirse para cualquier elemento del tipo
I
los problemas que reciban valores del tipo compuesto como
argumentos pueden suponer que se cumplen los invariantes
tipo T {
observador . . . ;
..
.
especificar el problema de construir un cı́rculo a partir de
I
su centro y su radio
invariante R(x);
problema nuevoCı́rculo(c : Punto, r : Float) = res : Cı́rculo {
requiere r > 0;
asegura (Centro(res) == c ∧ Radio(res) == r );
}
I
}
I
su centro y un punto sobre la circunferencia:
problema probA(. . . , x : T, . . . ) = . . . {
requiere . . . ∧ R(x) ∧ . . . ;
| {z }
no hace falta
asegura . . . ;
}
los que devuelven resultados de ese tipo tienen que asegurar
que no se violen
problema probB(. . . ) = r : T {
requiere . . . ;
asegura Q(r ) −→ Q(r ) debe ser más fuerte que R(r )
}
problema nuevoCı́rculoPuntos(c, x : Punto) = res : Cı́rculo {
requiere dist(c, x) > 0;
asegura (Centro(res) == c ∧ Radio(res) == dist(c, x));
}
5
Tipo MatrizhT i
Tipos genéricos
I
I
en los ejemplos vistos, cada componente es de un tipo
determinado de antemano
también hay tipos compuestos que representan una estructura
I
I
I
I
definen una familia de tipos
I
los problemas que usen un tipo genérico definen una familia de
problemas
cada elemento de la familia es una instancia del tipo genérico
permiten definir funciones auxiliares o especificar problemas
I
genéricos: su descripción depende únicamente de la estructura
del tipo genérico
especı́ficos de un tipo: su descripción solo tiene sentido para
un cierto tipo
I
I
ejemplo: una instancia del tipo genérico MatrizhT i es
MatrizhChari
I
el nombre del tipo tiene parámetros
I
tipo genérico de las matrices cuyos elementos pertenecen a un
tipo cualquiera T
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);
precondición del observador
requiere 0 ≤ c < columnas(m); }
invariante filas(m) > 0;
invariante columnas(m) > 0;
}
se llaman tipos genéricos o tipos paramétricos
I
I
I
su contenido van a ser valores no siempre del mismo tipo
comportamiento uniforme
I
I
6
I
variables que representan a los tipos de los componentes
los parámetros de tipo se escriben entre los sı́mbolos h y i
después del nombre del tipo
el tipo de matrices cuyos elementos son caracteres
un tipo genérico define una familia (infinita) de tipos
I
algunos miembros de la familia MatrizhT i son
MatrizhInti ,
7
MatrizhPuntoi ,
MatrizhMatrizhFloatii
8
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)))
(∀j ← [0..columnas(m)), ¬(i == f ∧ j == c))
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
10
9
El tipo SecuenciahT i
Operaciones genéricas con secuencias
I
I
ya lo usamos con su nombre alternativo: [T ]
I
presentamos también sus observadores: longitud e indexación
I
I
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
}
}
I
I
I
I
I
I
notaciones alternativas
I
I
podemos definir
|s| para la longitud
si o s[i] para la indexación
11
aux ssc(a, b : [T ]) : Bool =
(∀i ← [0..|b| − |a|)) a == b[i..(i + |a|));
aux cab(a : [T ]) : T = a[0];
aux cola(a : [T ]) : [T ] = a[1..|a|);
aux en(t : T , a : [T ]) : Bool = [x | x ← a, x == t] 6= [ ];
aux sub(a : [T ], d, h : Int) : [T ] =
[a[i] | i ← [d..h], (0 ≥ ∧h < |a|)];
aux todos(sec : [Bool]) : Bool = false ∈
/ sec;
aux alguno(sec : [Bool]) : Bool = true ∈ sec;
I
para algunas no usamos directamente los observadores
I
aprovechamos la notación de listas por comprensión
I
el selector es parte de la notación de listas por comprensión
(estructura especial de nuestro lenguaje de especificación)
12
Operaciones sobre secuencias para tipos instanciados
I
I
Tuplas
para representar textos (cadenas de caracteres) usamos el tipo
SecuenciahChari (o [Char])
queremos ver si alguna palabra de una lista aparece en un libro
I
I
I
problema hayAlguna(palabras : [[Char]], libro : [Char]) = res : Bool{
requiere NoVacı́as : (∀p ← palabras) |p| > 0;
requiere SinEspacios : ¬(∃p ← palabras) ‘ ‘ ∈ p;
asegura res == (∃p ← palabras) ssc(p, libro);
}
I
secuencias que en cada posición tienen una secuencia de
caracteres
tipo TernahA, B, C i{
observador prm3(t : TernahA, B, C i) : A;
observador sgd3(t : TernahA, B, C i) : B;
observador trc3(t : TernahA, B, C i) : C ;
}
precondiciones
I
I
I
tipo ParhA, Bi{
observador prm(p : Par hA, Bi) : A;
observador sgd(p : Par hA, Bi) : B;
}
lista de palabras: tipo [[Char]] o SecuenciahSecuenciahCharii
I
I
I
ya las mencionamos
secuencias de tamaño fijo
cada elemento puede pertenecer a un tipo distinto
ejemplos: pares, ternas
cada palabra debe tener al menos una letra
no contienen ningún espacio (dejarı́an de ser palabras)
en vez de SinEspacios: que las palabras no contengan ningún
sı́mbolo que no sea una letra
I
notación
I
requiere SinSı́mbolos: (∀p ← palabras) soloLetras(p);
aux letras: [Char ] = [‘A‘..‘Z ‘] + +[‘a‘..‘z‘];
aux soloLetras(s : [Char]) : Bool = (∀l ← s) l ∈ letras;
I
ParhA, Bi también se puede escribir (A, B)
TernahA, B, C i también se puede escribir (A, B, C )
13
ifThenElsehT i
14
Más aplicaciones de IfThenElse
Función que elige entre dos elementos del mismo tipo, según una
condición (guarda)
I
I
si la guarda es verdadera, elige el primero
si no, elige el segundo
I
aux cons(x : T , a : [T ]) : [T ] =
[if i == −1 then x else a[i] | i ← [−1..|a|)];
Por ejemplo
I
I
expresión que devuelve el máximo entre dos elementos:
cuando los argumentos se deducen del contexto, se puede
escribir directamente
I
concatenar dos listas
aux conc(a, b : [T ]) : [T ] =
[if i < |a| then a[i] else b[i − |a|] | i ← [0..|a| + |b|)];
aux máx(a, b : Int) : Int = ifThenElsehInti(a > b, a, b)
aux máx(a, b : Int) : Int = ifThenElse(a > b, a, b)
aux máx(a, b : Int) : Int = if a > b then a else b
agregar un elemento como primer elemento de una lista
I
o bien
cambiar el valor de una posición
aux cambiar(a : [T ], i : Int, v : T ) : [T ] =
[if i 6= j then a[i] else v | j ← [0..|a|)];
expresión que dado x devuelve 1/x si x 6= 0 y 0 sino
aux unoSobre(x : Float) : Float = if x 6= 0 then 1/x else 0
|
{z
}
no se indefine cuando x = 0
15
16
Descargar