Programación Funcional Avanzada

Anuncio
Programación Funcional Avanzada - Práctico 1
26-08-2016 → 09-09-2016
1. Considere los módulos
module A (S (), module B ) where
import Prelude ()
import B (T (. .))
data S = C | D
module B (T (D)) where
data T = C | D
(a) ¿Qué nombres exporta el módulo A?
(b) ¿Qué nombres están en el alcance del cuerpo del módulo A y dónde
están definidos? Si existen nombres ambiguos, lı́stelos.
2. En Haskell, una (sub-) expresión puede ser anotada explı́citamente con un
tipo utilizando (::). Por ejemplo, si escribimos:
x = [[ ]]
el tipo de x es [[a]] y si escribimos:
x = [[ ] :: [Int ]]
el tipo es [[Int]]. Utilizando módulos, muestre un pequeño programa donde
a una (sub-) expresión no se le puede anotar su tipo.
Pruebe en GHC y muestre los mensajes de error obtenidos.
3. Considere las siguientes definiciones:
data Tree a = Empty
| Node (Tree a) a (Tree a)
deriving Show
size :: Tree a → Int
size Empty
=0
size (Node l r ) = size l + 1 + size r
1
length :: [a ] → Int
length [ ]
=0
length (x : xs) = 1 + length xs
flatten :: Tree a → [a ]
flatten Empty
= []
flatten (Node l a r ) = flatten l ++ [a ] ++ flatten r
(+
+) :: [a ] → [a ] → [a ]
[] +
+ ys
= ys
(x : xs) +
+ ys = x : (xs ++ ys)
Demuestre el siguiente Teorema utilizando razonamiento ecuacional:
∀ (t :: Tree a).length (flatten t) ≡ size t
Previamente demuestre el siguiente Lema, que le será útil para demostrar
el Teorema:
∀ (xs :: [a ]) (ys :: [a ]).length (xs ++ ys) ≡ length xs + length ys
Recuerde que (+) es asociativo y 0 es su elemento neutro.
4. Escriba un módulo Haskell con todas las definiciones del ejercicio anterior.
Importe QuickCheck y defina una instancia de Arbitrary para poder probar propiedades parametrizadas por Trees.
instance Arbitrary a ⇒ Arbitrary (Tree a)
...
Defina propiedades QuickCheck para el Teorema y Lema del ejercicio anterior.
Defina una función mirror que invierta un árbol, y defina propiedades
QuickCheck para verificar que:
(a) invertir un árbol y luego aplicarle flatten es lo mismo que aplicar
flatten a un árbol y luego invertir (reverse) la lista resultante
(b) invertir dos veces un árbol resulta en el árbol original
(c) el tamaño de un árbol invertido es el mismo que el tamaño del árbol
original.
Analice los datos de prueba generados utilizando collect.
5. Dado el siguiente término:
(λx .λy.y x ) ((λx .(λy.x (y y)) (λy.x (y y))) (λx .x z )) (λx .λy.y)
(a) Indique cuales ocurrencias de variables son ligaduras, ligadas y libres.
2
(b) Liste los β-redexes que tiene el término.
(c) ¿Cuántas formas normales tiene el término? Escriba una secuencia
de β-reducciones que llegue a una forma normal.
6. Considere las codificaciones de booleanos, pares y naturales en términos
del cálculo lambda vistas en clase. Usando las mismas defina las siguientes
funciones:
(a)
(b)
(c)
(d)
SWAP , que intercambia las componentes de un par
DUP , que duplica un natural
EXP2 , que retorna el exponente en base 2 de un natural
PRED, que retorna el predecesor de un natural (considere que el
predecesor de cero es cero).
(e) IFTE , que dado un booleano y dos términos implementa if-then-else.
7. En el cálculo lambda las funciones recursivas se codifican utilizando combinadores de “punto fijo”. Un ejemplo de estos combinadores es:
fix = λf → (λx → f (x x )) (λx → f (x x ))
Este combinador no es recursivo, pero puede ser usado para definir funciones recursivas debido a la siguiente propiedad (si quiere puede intentar
demostrarla usando razonamiento ecuacional):
fix f ≡ f (fix f )
(a) Explique brevemente por qué este combinador no se puede tipar correctamente en Haskell.
(b) Si definimos fix (utilizando la recursión de Haskell) como:
fix f = f (fix f )
¿Cuál es su tipo?
(c) Considere la siguiente definición de la función suma:
suma n = if n ≡ 0 then 0 else n + suma (n − 1)
Defina esta función utilizando fix .
8. (OPCIONAL) Considere nuevamente las codificaciones de booleanos, pares
y naturales en términos del cálculo lambda. Usando dicha codificación defina la función suma del ejercicio anterior de la siguientes formas:
(a) Usando la formulación presentada en el ejercicio anterior y el operador Y de punto fijo visto en clase.
(b) Directamente usando la codificación de los naturales, sin usar if-thenelse. Para ello considere la siguiente formulación de suma:
suma 0
=0
suma (n + 1) = n + 1 + suma n
3
Descargar