Parcial de Funcional Algoritmos y Estructuras de Datos I – 18/05/07 Aclaraciones: El parcial es a libro abierto. En el caso de usar resultados dados en clases prácticas o en las guı́as de ejercicios, se deben incluir las resoluciones. Cualquier decisión de interpretación que se tome debe ser aclarada y justificada. Para aprobar se requieren al menos 60 puntos. Indicar el número de orden, LU y la cantidad total de hojas entregadas. Entregar cada ejercicio en hojas separadas. Tipos algebraicos. Se cuenta con el tipo compuesto ListaAc que modela una lista de elementos con longitud acotada. Si bien la cantidad máxima de elementos en una ListaAc tiene un tope, éste puede aumentarse redimensionando la lista. Si l es de tipo ListaAc, el observador elementos(l) devuelve los elementos de l, desde el primero hasta el último, listados de izquierda a derecha. El observador capacidad(l) devuelve la cantidad máxima de elementos que una ListaAc puede almacenar (teniendo en cuenta los eventuales redimensionamientos). El observador redims(l) devuelve la cantidad de veces que la lista fue redimensionada desde su creación. tipo ListaAchai { observador capacidad (l : ListaAchai) : Z observador elementos (l : ListaAchai) : [a] observador redims (l : ListaAchai) : Z invariante capacidad(l) ≥ |elementos(l)| invariante redims(l) ≥ 0 } Se busca implementar en Haskell algunos problemas sobre el tipo compuesto ListaAc mediante el tipo algebraico ListaAc. Dicho tipo está definido con los siguientes constructores data ListaAc a = Vacia Int | Aumentar Int (ListaAc a) | Cons a (ListaAc a) que permiten crear una lista vacı́a con una capacidad inicial determinada, aumentar la capacidad de la lista y agregar un elemento a la lista respectivamente. También se cuenta con los siguientes problemas: problema redimensionar(l : ListaAchai, n : Z) = res : ListaAchai { requiere n > 0; asegura elementos(res) == elementos(l); asegura capacidad(res) == capacidad(l) + n; asegura redims(res) == redims(l) + 1; } problema agregar(x : a, l : ListaAchai) = res : ListaAchai { requiere capacidad(l) > |elementos(l)|; asegura capacidad(res) == capacidad(l); asegura elementos(res) == x : elementos(l); asegura redims(res) == redims(l); } problema crear(n : Z) = res : ListaAchai { requiere n ≥ 0; asegura elementos(res) == []; asegura capacidad(res) == n; asegura redims(res) == 0; } Y, respectivamente, las siguientes implementaciones en Haskell: redimensionar:: ListaAc a → Int → ListaAc a redimensionar l n = Aumentar n l agregar:: a → ListaAc a → ListaAc a agregar x l = Cons x l crear:: Int → ListaAc a crear n = Vacia n Ejercicio 1. (35 puntos) Implementar los siguientes problemas: a) (5 puntos) problema capacidad(l : ListaAchai) = res : Z { asegura res == capacidad(l); } b) (10 puntos) problema simplificar(l : ListaAchai) = res : ListaAchai { asegura elementos(res) == elementos(l); asegura capacidad(res) == capacidad(l); asegura redims(res) == 0; } c) (20 puntos) problema igualar(l : [ListaAchZi]) = res : [ListaAchZi] { asegura |l| == |res|; asegura (∀i ∈ [0..|l|))(capacidad(resi ) == capMax(l) ∧ libres(resi ) == libres(li )); asegura (∀i ∈ [0..|l|))prefijo(elementos(li ), elementos(resi )); } aux capMax(l : [ListaAchai]) : Z = maximo([capacidad(x)|x ∈ l]) aux libres(l : ListaAchai) : Z = capacidad(l) − |elementos(l)| aux prefijo(x, y : [a]) = y[0..|x|) == x Tipos abstractos. Se cuenta con el tipo compuesto Aldea, que representa el lugar donde habitan los pitufos. Si a es de tipo Aldea, pitufos(a) devuelve una lista sin duplicados de los pitufos que viven en esa aldea. Si p y q son dos pitufos de a, sonAmigos(a, p, q) devuelve verdadero sii los pitufos p y q son amigos entre sı́. Por otro lado, si p es de tipo Pitufo, nombre(p) y profesion(p) devuelven, respectivamente, el nombre y la profesión del pitufo. tipo Aldea { observador pitufos (a : Aldea) : [Pitufo] observador sonAmigos (a : Aldea, p : Pitufo, q : Pitufo) : Bool requiere p, q ∈ pitufos(a); invariante (∀p, q ∈ pitufos(a))sonAmigos(a, p, q) ↔ sonAmigos(a, q, p) invariante sinRepetidos(pitufos(a)) } tipo Pitufo { observador nombre (p : Pitufo) : Nombre observador profesion (p : Pitufo) : Profesion } tipo Nombre = [Char] tipo Profesion = [Char] El tipo Pitufo está implementado en funcional con las operaciones nombre:: Pitufo → Nombre y profesion:: Pitufo → Profesion para los observadores nombre y profesion respectivamente. De manera similar, el tipo Aldea está implementado con las operaciones pitufos:: Aldea → [Pitufo] y sonAmigos:: Aldea → Pitufo → Pitufo → Bool para los observadores pitufos y sonAmigos. Ejercicio 2. (30 puntos) Implementar en funcional el siguiente problema: problema pitufoAmistoso (a : Aldea) = res : Pitufo { requiere (∃p ∈ pitufos(a)); asegura res ∈ pitufos(a); asegura (∀p ∈ pitufos(a))cantidadAmigos(a, res) ≥ cantidadAmigos(a, p); aux cantidadAmigos(a : Aldea, p : Pitufo) : Z = |[q | q ∈ pitufos(a), sonAmigos(a, p, q)]|; } Ejercicio 3. (35 puntos) Implementar en funcional el siguiente problema: problema pitufosPorProfesion (a : Aldea) = res : [[Pitufo]] { asegura mismos(pitufos(a), aplanar(res)); asegura (∀ps ∈ res, ∀p, q ∈ ps)profesion(p) == profesion(q); asegura (∀p, q ∈ aplanar(res), (¬∃ps ∈ res)(p ∈ ps ∧ q ∈ ps))profesion(p) 6= profesion(q); aux aplanar(ps : [[Pitufo]]) : [Pitufo] = [x|xs ∈ ps, x ∈ xs]; }