Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
teaching:cc4101:tareas:2015-2:tarea3 [2016/03/20 04:38] fmossoteaching:cc4101:tareas:2015-2:tarea3 [2016/03/25 18:42] (current) – old revision restored (2015/10/31 14:36) fmosso
Line 135: Line 135:
 Aquí ocurre que por el tipo del argumento, reemplazar en esa expresión ''%%f%%'' por ''%%h%%'' también es válido pues si ''%%f%%'' puede ser aplicado a un ''%%Num%%'', con mayor razón una función que espera un tipo más general, en este caso ''%%Any%%''. Aquí ocurre que por el tipo del argumento, reemplazar en esa expresión ''%%f%%'' por ''%%h%%'' también es válido pues si ''%%f%%'' puede ser aplicado a un ''%%Num%%'', con mayor razón una función que espera un tipo más general, en este caso ''%%Any%%''.
 Entienda la función ''%%typeof-with-sub%%'' para que incluya esta relación de subtipos de funciones Entienda la función ''%%typeof-with-sub%%'' para que incluya esta relación de subtipos de funciones
 +===== (1.0) Sistema de tipos extendido con casts =====
 +Vamos a explicar como se comportan los cast con un ejemplo en Java <code java>
 +public void foo(Object obj){
 +  String str = (String)obj;
 +}
 +</code>
 +En este caso el programador está intentando hacer un cast de Object a String. Esto tiene dos implicancias sobre el lenguaje. Primero, el cast funciona estáticamente como una forma que tiene el programador de expresarle al sistema de tipos que cierto valor tiene cierto tipo, permitiendole en este caso asignar ''%%obj%%'' (que es originalmente un Object) a un identificador que espera un String. Segundo, el lenguaje no puede asegurar que el programador no se equivocó, por lo tanto añade en el bytecode generado, una pequeña validación de tipos en runtime que, en caso de fallo lanza un ClassCastException. 
 +==== Cast para tipos simples ====
 +Considere: <code scheme>
 +{with : Num {id : (Any -> Any)
 +            {fun {x : Any} : Any x}}
 +        {+ 1 {id 2}}}
 +</code>
 +Este programa es rechazado por el sistema de tipos pues ''%%{f 2}%%'' tiene tipo ''%%Any%%'' y no ''%%Num%%''. Podemos agregar un cast para decirle al sistema de tipos que el resultado si es un ''%%Num%%'' para que ahora el sistema de tipos acepte el programa: <code scheme>
 +{+ 1 {cast Num {id 2}}}
 +</code>
 +En tiempo de ejecución, tal como en el caso en Java, puede ocurrir que el elemento casteado no retorne un Num. Para evitar que la maquina terminare con un SEGFAULT se hace una válida dinámica en la máquina para un cast.
 +  - Implemente la función ''%%(typeof-with-cast expr)%%'' que recibe un nodo del AST y retorna el tipo correspondiente a él o falla en caso de que la expresión no sea válida. Considere que ''%%(typeof-with-cast expr)%%'' se comporta igual que la función ''%%(typeof-with-sub expr)%%'' de la pregunta anterior, salvo que ahora trabajará con casts. Además:
 +    * Añada ''%%cast%%'' a la gramática y al AST de expresiones
 +    * Modifique las funciones ''%%parse%%'' y ''%%deBruijn%%''  para soportar el nuevo nodo ''%%cast%%'' <code scheme>
 +> (parse '{cast Num #f})
 +(cast (TNum) (bool #f))
 +</code>
 +  - Actualice la función ''%%çompile%%'' para que genere un ''%%CHECKCAST%%'' para un expresión ''%%cast%%''. <code scheme>
 +> (compile (parse '{cast Num (and #t #f)}))
 +(list (BOOL_CONST #f) (BOOL_CONST #t) (AND) (CHECKCAST (MTNum)))
 +</code>
 +  - Implemente la función ''%%(typed-compile s-expr)%%'' que se encarga de todo el proceso de generación de código desde una ''%%S-Expr%%'', considerando el parsing, la nueva validación de tipos, la transformación con índices De Bruijn y el paso a listas de instrucciones que considera incluir la instrucción ''%%(CHECKCAST type)%%'' para hacer validación dinámica de tipos.
  
 +==== Casts para funciones ====
 +El siguiente ejemplo no se puede ejecutar actualmente pues el sistema de tipos lo rechaza. <code scheme>
 +{with : Bool {id : (Any -> Any)
 +                           {fun {x : Any} : Any x}}
 +                {with : Bool {g : ((Bool -> Bool) -> Bool)
 +                                {fun {f : (Bool -> Bool)} : Bool {f #t}}}
 +                      {with : Bool {f : (Bool -> Bool)
 +                                      {fun {x : Bool} : Bool x}}
 +                            {g {id f}}}}}
 +</code>
 +Esto sería solucionable si pudiésemos también castear funciones de la siguiente la forma: <code scheme>
 +{cast (Bool -> Bool) {id f}}
 +</code>
 +Teniendo una forma de castear funciones, podemos hacer que el sistema de tipos acepte el código anterior.
 +<code scheme>
 +{with : Bool {id : (Any -> Any)
 +                          {fun {x : Any} : Any x}}
 +               {with : Bool {g : ((Bool -> Bool) -> Bool)
 +                               {fun {f : (Bool -> Bool)} : Bool {f #t}}}
 +                     {with : Bool {f : (Bool -> Bool)
 +                                     {fun {x : Bool} : Bool x}}
 +                           {g {cast (Bool -> Bool) {id f}}}}}}
 +</code>
 +Para que la máquina sea capaz de realizar un cast entre funciones, debe implementar la función ''%%(m-subtype? mT1 mT2)%%'' del fichero machine.rkt. La función ''%%m-subtype?%%'' evalúa a ''%%#t%%'' si ''%%mT1%%'' es subtipo de ''%%mT2%%'' incluyendo la noción de subtipos entre funciones <code scheme>
 +> (m-subtype? (MTFun (MTNum) (MTNum))
 +              (MTFun (MTNum) (MTAny)))
 +#t
 +</code>