Pruebas sobre el intérprete¶
Pruebas de chequeo de tipos¶
A continuación se presentan pruebas ejecutadas sobre el intérprete de tipos, mostrando tanto casos exitosos como errores detectados.
; Prueba 1: Tipo de una variable simple en un let
(type-of-program (scan&parse "let x = 10 in x"))
; Resultado: #(struct:atomic-type int)
; El tipo de x es int, ya que 10 es un literal numérico
> (type-to-external-form (type-of-program (scan&parse "let x = 10 in x")))
; Resultado: int
; type-to-external-form convierte la representación interna a formato legible
; Prueba 2: Tipo de un procedimiento como valor
> (type-to-external-form (type-of-program (scan&parse "let x = proc(int a, int b) +(a,b) in x")))
; Resultado: (int * int -> int)
; El tipo de x es el tipo del procedimiento: recibe dos int y retorna int
; Prueba 3: Aplicación correcta de un procedimiento
> (type-to-external-form (type-of-program (scan&parse "let x = proc(int a, int b) +(a,b) in (x 1 2)")))
; Resultado: int
; (x 1 2): x espera (int * int), 1 es int, 2 es int (match), retorna int
; Prueba 4: Error por tipo incorrecto en argumento
> (type-to-external-form (type-of-program (scan&parse "let x = proc(int a, int b) +(a,b) in (x 1 true)")))
; Resultado: . . check-equal-type!: Types didn’t match: bool != int in
; #(struct:true-exp)
; Error: Se esperaba int como segundo argumento, pero se proporcionó true (bool)
; El chequeo de tipos detecta la inconsistencia en tiempo de análisis estático
; Prueba 5: Error por número incorrecto de argumentos
> (type-to-external-form (type-of-program (scan&parse "let x = proc(int a, int b) +(a,b) in (x 1 2 3)")))
; Resultado: . . type-of-expression: Wrong number of arguments in expression
; #(struct:app-exp #(struct:var-exp x) (#(struct:lit-exp 1) #(struct:lit-exp 2) #(struct:lit-exp 3))):
; expected (int int)
; got (int int int)
; Error: x espera exactamente 2 argumentos, pero se proporcionaron 3
; Prueba 6: Procedimiento recursivo con letrec (caso exitoso)
(type-to-external-form (type-of-program (scan&parse "letrec
int f(int a, bool b) = if b then +(a, (f -(a,1) <(a,0))) else a in (f 3 true)")))
; Resultado: int
; f: (int * bool) -> int
; (f 3 true): 3 es int, true es bool (match), retorna int
; El cuerpo recursivo es consistente: -(a,1) es int, <(a,0) es bool, f espera (int * bool)
; Prueba 7: Tipo del procedimiento recursivo como valor
> (type-to-external-form (type-of-program (scan&parse "letrec
int f(int a, bool b) = if b then +(a, (f -(a,1) <(a,0))) else a in f")))
; Resultado: (int * bool -> int)
; Al evaluar f directamente (sin aplicarlo), obtenemos su tipo como valor de procedimiento
; Prueba 8: Error por inconsistencia en las ramas del if
> (type-to-external-form (type-of-program (scan&parse "letrec
int f(int a, bool b) = if b then +(a, (f -(a,1) <(a,0))) else b in f")))
; Resultado: . . check-equal-type!: Types didn’t match: int != bool in
; #(struct:if-exp #(struct:var-exp b)
; #(struct:primapp-exp #(struct:add-prim)
; (#(struct:var-exp a)
; #(struct:app-exp #(struct:var-exp f)
; (#(struct:primapp-exp #(struct:substract-prim) (#(struct:var-exp a) #(struct:lit-exp 1)))
; #(struct:primapp-exp #(struct:menor-prim) (#(struct:var-exp a) #(struct:lit-exp 0)))))))
; #(struct:var-exp b))
; Error: La rama then retorna int (por la suma +(a, ...)), pero la rama else retorna bool (b)
; El if requiere que ambas ramas tengan el mismo tipo
Tabla resumen de conceptos¶
| Concepto | Descripción | Ejemplo de prueba |
|---|---|---|
| type-of-program | Función que calcula el tipo de un programa completo a partir de su representación interna | (type-of-program (scan&parse "let x = 10 in x")) retorna atomic-type int |
| type-to-external-form | Función que convierte la representación interna de tipos a formato legible | (type-to-external-form ...) retorna int, (int * int -> int) |
| scan&parse | Función que analiza sintácticamente una cadena y produce un AST (Árbol de Sintaxis Abstracta) | (scan&parse "let x = 10 in x") |
| Tipo atómico | Tipo básico como int o bool | #(struct:atomic-type int) |
| Tipo de procedimiento | Tipo compuesto que describe argumentos y retorno | (int * bool -> int) |
| Aplicación correcta | Cuando los tipos de los argumentos coinciden con los esperados | (x 1 2) con x: (int * int -> int) |
| Error de tipo en argumento | Cuando un argumento no coincide con el tipo esperado | (x 1 true) espera int, recibe bool |
| Error de número de argumentos | Cuando se proporcionan más o menos argumentos de los esperados | (x 1 2 3) espera 2, recibe 3 |
| Inconsistencia en if | Cuando las ramas then y else del if no tienen el mismo tipo | if b then +(a, ...) else b then retorna int, else retorna bool |
| Recursión en letrec | Permite que un procedimiento se llame a sí mismo con tipos consistentes | f -(a,1) <(a,0) donde f espera (int * bool) |
Comentarios adicionales:
- El intérprete de tipos utiliza un enfoque compositional: cada expresión tiene reglas de tipado que dependen únicamente de los tipos de sus subexpresiones.
- Los errores se reportan con información detallada: muestran la expresión exacta donde ocurre el error y los tipos que entraron en conflicto.
- La función type-to-external-form es útil para depuración, ya que presenta los tipos en un formato más legible que la representación interna con structs.
- El chequeo de tipos en letrec requiere que el tipo del procedimiento esté disponible en el ambiente antes de verificar el cuerpo, permitiendo así la recursión.
- Las pruebas muestran que el sistema detecta tres tipos de errores: tipo incorrecto, número incorrecto de argumentos e inconsistencia en las ramas del condicional.