Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
teaching:cc4101:tareas:2021-1:tarea1 [2021/04/12 21:35] – removed tvallejos | teaching:cc4101:tareas:2021-1:tarea1 [2021/05/10 14:34] (current) – P3, add '}' on first example bortiz | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Tarea 1 (Entrega: 7 de mayo de 2021) ====== | ||
+ | |||
+ | ==== Tipos estáticos, tipos opcionales, contratos ==== | ||
+ | |||
+ | Ya se habrán dado cuenta que ciertos lenguajes tienen tipos estáticos (C/C++, Java, C#, Scala, etc.) y otros tienen tipos dinámicos (Python, Racket, JavaScript, etc.). Más aún, ciertos lenguajes como Racket tienen contratos, que permiten expresar propiedades más finas. Además, muchos lenguajes originalmente dinámicos ahora tienen tipos opcionales (Python, TypeScript, Hack, etc.). | ||
+ | |||
+ | En esta tarea van a dejar atrás toda confusión al respecto! Van a implementar un lenguaje simple (con funciones de primer orden, tipos de datos básicos, y operadores sobre ellos), primero con sólo checkeo dinámico de tipos (parte 1), luego le van a agregar verificación de tipos estáticos (parte 2), incluyendo tipos opcionales con un tipo " | ||
+ | |||
+ | Al final de esta tarea, tendrán implementado un lenguaje bastante original que permite mezclar checkeo estático y dinámico de tipos y propiedades! | ||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | |||
+ | <note important> | ||
+ | Recuerden que tienen que seguir la metodología [[https:// | ||
+ | </ | ||
+ | |||
+ | |||
+ | Deben entregar via U-cursos **un archivo .zip** que contenga los siguientes archivos: '' | ||
+ | |||
+ | |||
+ | <note important> | ||
+ | Cada parte de esta tarea vale lo mismo: 2 puntos. La asignación de puntaje por parte sigue la misma estructura: | ||
+ | * 0.2 para soportar la sintaxis indicada (parser bien definido y estructurado) | ||
+ | * 1.5 para las funcionalidades (p.ej. interprete para la P1) | ||
+ | * 0.3 para testing (cobertura de todos los casos relevantes) | ||
+ | </ | ||
+ | |||
+ | ===== Parte 1. Lenguaje con funciones de primer orden ===== | ||
+ | En esta parte, vamos a implementar un lenguaje que incluye primitivas útiles (números, booleanos, y sus operadores), | ||
+ | |||
+ | Aquí está la gramática BNF del lenguaje: | ||
+ | <code scheme> | ||
+ | < | ||
+ | |||
+ | < | ||
+ | |||
+ | < | ||
+ | | <id> | ||
+ | | < | ||
+ | | {< | ||
+ | | {< | ||
+ | | {if < | ||
+ | | {with {{< | ||
+ | | {<id> < | ||
+ | |||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | Un programa está compuesto de (0 o más -- por eso la estrella '' | ||
+ | |||
+ | < | ||
+ | |||
+ | Algunos ejemplos de programas válidos para este lenguaje pueden ser: | ||
+ | <code scheme> | ||
+ | { ;; Programa de Ejemplo 1 | ||
+ | | ||
+ | | ||
+ | {with {{x 9}} | ||
+ | {sum {max x 6} 2 -10} } | ||
+ | } | ||
+ | { ;; Programa de Ejemplo 2 | ||
+ | {with {{x 5} {y 7} {z 42}} | ||
+ | z} | ||
+ | } | ||
+ | { ;; Programa de Ejemplo 3 | ||
+ | | ||
+ | | ||
+ | {add2 {triple 2}} | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | En esta parte, su función '' | ||
+ | |||
+ | **Instrucciones importantes**: | ||
+ | * Para implementar el lenguaje, tiene que [[https:// | ||
+ | * Tienen que verificar que los argumentos de los operadores booleanos sean booleanos (eso para alinear la verificación dinámica con la verificación estática que harán en la parte 2) | ||
+ | * En caso de programas con errores dinámicos, su interprete tiene que reportarlos explícitamente. Por ejemplo: | ||
+ | |||
+ | <code scheme> | ||
+ | debe caerse en tiempo de ejecución con un error (se levantan con '' | ||
+ | <code scheme>" | ||
+ | Recuerde que puede testear estos errores con '' | ||
+ | |||
+ | |||
+ | ----- | ||
+ | ===== Parte 2. Verificación estática y opcional de tipos ===== | ||
+ | En esta parte vamos a extender el lenguaje de la Parte 1 con anotaciones de tipos y verificación estática de ellos. Las diferencias en la sintaxis del lenguaje respecto de la parte anterior son: | ||
+ | * las declaraciones de función aceptan anotaciones de tipos en cada uno de sus argumentos, y también para el retorno | ||
+ | * las expresiones '' | ||
+ | |||
+ | Observe que las anotaciones de tipos son siempre *opcionales* (en el BNF aquí usamos '' | ||
+ | <code scheme> | ||
+ | < | ||
+ | |||
+ | < | ||
+ | |||
+ | < | ||
+ | |||
+ | < | ||
+ | </ | ||
+ | |||
+ | Note que '' | ||
+ | |||
+ | Para soportar la verificación opcional, lo que haremos es introducir un tipo comodín '' | ||
+ | |||
+ | < | ||
+ | Obviamente, usar el tipo '' | ||
+ | </ | ||
+ | |||
+ | Los programas siguientes son válidos, y bien tipados: | ||
+ | <code scheme> | ||
+ | {{with {{x : Num 5} {y : Num 10}} {+ x y}}} | ||
+ | |||
+ | {{define {gt42 x} : Bool {> x 42}} | ||
+ | {gt42 43}} | ||
+ | |||
+ | {{define {id {x : Num}} x} | ||
+ | {id 5}} | ||
+ | |||
+ | {{define {add2 {x : Num}} {+ x 2}} | ||
+ | {with {{oops #f}} | ||
+ | {add2 oops}}} | ||
+ | </ | ||
+ | |||
+ | En particular, fíjese que el último ejemplo está bien tipado solamente porque se usa '' | ||
+ | |||
+ | En esta parte, deben definir una nueva función '' | ||
+ | |||
+ | **Instrucciones**: | ||
+ | * Recuerden que la gramática BNF dicta la estructura de sus definiciones | ||
+ | * La verificación de tipos de un programa consiste en verificar que todas las definiciones de función estén bien tipadas, y que la última expresión tiene un tipo (no importa cual). | ||
+ | * Para una definición de función, se valida que la expresión del cuerpo tenga el mismo tipo que el tipo de retorno declarado, suponiendo que cada argumento tiene el tipo declarado. Recuerde que si no se especifica un tipo, se considera '' | ||
+ | * Debe definir los tipos de los operadores primitivos de manera exacta, p.ej. '' | ||
+ | * Para una expresión '' | ||
+ | * Para '' | ||
+ | * En la aplicación de función se valida que el número de argumentos coincide, y que el tipo de los argumentos coincide con los tipos esperados de la función aplicada. La aplicación en sí tiene el tipo de retorno de la función aplicada. | ||
+ | |||
+ | Para los errores: | ||
+ | * Los errores de identificadores libres (o funciones no definidas) se tienen que detectar estáticamente, | ||
+ | * Los mensajes de error de tipo detectados estáticamente tienen que seguir el siguiente patrón: | ||
+ | <code scheme>" | ||
+ | |||
+ | Algunos ejemplos (no representan todos los casos, es de su responsabilidad entregar //test suites// completos): | ||
+ | < | ||
+ | > (typecheck '{3}) | ||
+ | ' | ||
+ | > (typecheck ' | ||
+ | {f {> 3 4}}}) | ||
+ | 'Any </ | ||
+ | > (typecheck ' | ||
+ | {one #t}}) | ||
+ | " | ||
+ | > (typecheck ' | ||
+ | " | ||
+ | > (typecheck '{{if 73 #t #t}}) | ||
+ | " | ||
+ | > (typecheck ' | ||
+ | z}}) | ||
+ | " | ||
+ | |||
+ | ¿Puede efectivamente convencerse de que todo programa que pasa la verificación de tipo no se cae con un error de tipo durante la ejecución? | ||
+ | |||
+ | ---- | ||
+ | |||
+ | ===== Parte 3. Contratos en funciones de primer orden (2.0 pt) ===== | ||
+ | Ahora vamos a añadir verificación dinámica mediante contratos a las funciones de nuestro lenguaje. El único cambio en la sintaxis del lenguaje se ve reflejado en la definición de funciones, donde ahora se puede definir además un contrato para cada argumento: | ||
+ | <code scheme> | ||
+ | < | ||
+ | < | ||
+ | | {<id> [: < | ||
+ | </ | ||
+ | Un contrato corresponde a un predicado, una función que reciba exactamente un argumento y retorne un booleano. Un ejemplo de programa válido puede ser: | ||
+ | <code scheme> | ||
+ | {{define {positive x} : Bool {> x 0}} | ||
+ | | ||
+ | {/ y x}} | ||
+ | {div 5 3}} | ||
+ | </ | ||
+ | Donde el '' | ||
+ | |||
+ | Note que la información de tipo estático es opcional, por lo que uno puede especificar una función solamente mediante contratos. | ||
+ | <code scheme> | ||
+ | {{define {positive x} : Bool {> x 0}} | ||
+ | | ||
+ | {/ y x}} | ||
+ | {div 5 3}} | ||
+ | </ | ||
+ | |||
+ | En esta parte, su función '' | ||
+ | |||
+ | **Instrucciones**: | ||
+ | * En el intérprete, | ||
+ | * Cuando el contrato no se cumpla, el patrón de error es: <code scheme> | ||
+ | " | ||
+ | </ | ||
+ | * Para poder ser usado como contrato, una función *debe* tener aceptar un argumento de tipo '' | ||
+ | " | ||
+ | </ | ||
+ | |||
+ | Más ejemplos: | ||
+ | <code scheme> | ||
+ | {{define {lt100 x} {< x 100}} | ||
+ | | ||
+ | | ||
+ | | ||
+ | {/ {* y y} x}} | ||
+ | {calc 25 3}} | ||
+ | </ | ||
+ | |||
+ | <code scheme> | ||
+ | > (run ' | ||
+ | | ||
+ | #t} | ||
+ | | ||
+ | " | ||
+ | </ | ||