Inferencia de Tipos

Anuncio
Inferencia de Tipos
Paradigmas de Lenguajes de Programación
Primer cuatrimestre - 2008
Repasemos qué es “inferencia de tipos”
Dado un término U sin anotaciones de tipos, hallar un término M
tipable tal que:
1. Γ . M : σ para algún Γ y σ
2. Erase(M)=U
si U es tipable, y demostrar que no lo es en caso contrario.
Algunos ejemplos intuitivos
¿Qué tipo tienen...?
I
not False
I
1+2
I
Id (&&)
Axiomas y reglas de inferencia
x :σ∈Γ
(I-Var)
Γ.x :σ
(I-True)
Γ . true : Bool
(I-False)
Γ . false : Bool
(I-Zero)
Γ . 0 : Int
(Hasta acá son iguales que los axiomas y reglas de tipado.)
Reglas de inferencia
Γ ∪ {x : α} . e : β
(I-Abs)
Γ . λx.e : α → β
Γ . M : τ, S = MGU {τ =Int}
˙
(I-Succ)
S Γ . S (succ(M)) : S τ
Γ . M : τ, S = MGU {τ =Int}
˙
(I-Pred)
S Γ . S (pred(M)) : S τ
Γ.M : α, Γ0 .N : ρ, S = MGU({α=ρ
˙ → t}∪{σi =τ
˙ i /xi : σi ∈ Γ ∧ xi : τi ∈ Γ0 })
(I-App)
S Γ ∪ S Γ0 . S(M N) : S t
Extensiones
(I-Not)
Γ . not : Bool → Bool
(I-And)
Γ . && : Bool → Bool → Bool
(I-<)
Γ . < : Int → Int → Int
(I-+)
Γ . + : Int → Int → Int
(I-*)
Γ . ∗ : Int → Int → Int
(I-Id)
Γ . id : s → s
Tipado vs. Inferencia
Id es una constante polimórfica, una herramienta que nos
permiten las extensiones del lenguaje.
La regla de tipado para Id serı́a:
Γ . idσ : σ → σ
(T-Id)
Los términos que vamos a recibir van a venir sin anotaciones de
tipos en las constantes ni en las abstracciones (resultados de
Erase).
Al aplicar las reglas, las metavariables cuyos tipos no estén
definidos se van a reemplazar por variables de tipo frescas (es
decir, que no hayan sido usadas), y los términos polimórficos (en
esta clase Id y las abstracciones) se van a ir decorando.
Notación: vamos a denotar las variables de tipo con letras latinas, y las
metavariables con letras griegas.
Método del Árbol
Método del Árbol: paso por paso
1. Convencerse de que tipa (...o de que no tipa).
2. Convertir a notación prefija y hacer explı́citos todos los
paréntesis.
3. Construir el árbol de análisis sintáctico.
4. Aplicar las reglas sobre las hojas, indicando qué reglas,
unificaciones y sustituciones se aplican en cada paso.
5. Hacer lo mismo para los nodos internos a medida que sus
hijos queden resueltos.
6. Si se pudo tipar la raı́z, listo. Si no, indicar qué fue lo que falló.
Método del Árbol: más ejemplos
¿Qué tipo tienen...?
I
id not False
I
2 + True
I
λf.ff
¿Qué pasó?
¿Qué significa cuando Hugs dice “unification would give infinite
type”?
(O, para quien use ghc/ghci: “Occurs check: cannot construct the
infinite type: t = t − > t1”.)
Algoritmo PT (Principal Typing), o W
PT (x) = {x : t} . x : t, siendo t una variable de tipo fresca.
PT (succ(U)) : Si obtenemos del paso recursivo que:
PT (U) = Γ . M : τ
Construimos una sustitución que unifique τ con Int:
S = MGU{τ =Int}
˙
Entonces, devolvemos como resultado:
PT (succ(U)) = S Γ . S(succ(M)) : S τ
PT (pred(U)) : Si obtenemos del paso recursivo que:
PT (U) = Γ . M : τ
Construimos una sustitución que unifique τ con Int:
S = MGU{τ =Int}
˙
Entonces, devolvemos como resultado:
PT (pred(U)) = S Γ . S(pred(M)) : S τ
···
Algoritmo PT (continúa)
PT (UV ) : Si obtenemos de los pasos recursivos que:
PT (U) = Γ . M : τ
PT (V ) = Γ0 . N : ρ
(Asumimos que las variables de tipo de PT (U) y PT (V ) son disjuntas.)
Construimos una sustitución que unifique los contextos de tipado Γ y Γ0 :
S = MGU({α=β
˙ | x : α ∈ Γ ∧ x : β ∈ Γ0 } ∪ {τ =ρ
˙ → t}),
donde t es una variable de tipo fresca
Entonces, devolvemos como resultado:
PT (UV ) = SΓ ∪ SΓ0 . S(MN) : St
PT (λx.U) :
Si obtenemos del paso recursivo que:
PT (U) = Γ . M : ρ
Nos fijamos si habı́a información de tipado o no para la variable x.
Si x : τ ∈ Γ para algún τ :
PT (λx.U) = Γ − {x : τ } . λx : τ.M : τ → ρ
Si no:
PT (λx.U) = Γ . λx : s.M : s → ρ,
donde s es una variable de tipo fresca.
Algoritmo PT: extensiones
PT (not) = ∅ . not : Bool → Bool
PT (and) = ∅ . and : Bool → Bool → Bool
PT (<) = ∅. <: Int → Int → Bool
PT (+) = ∅ . + : Int → Int → Int
PT (∗) = ∅ . ∗ : Int → Int → Int
PT (Id) = ∅ . Idt : t → t siendo t una variable de tipo fresca.
En general, siempre que se quiera inferir el tipo de una constante
polimórfica, se usan variables de tipo frescas y se decora el término.
Para pensar...
¿Qué modificaciones habrı́a que hacerle al algoritmo si se
extendiera el lenguaje para contemplar pares hx, y i?
Para pensar...
Repasemos las reglas de tipado para pares:
Γ.M :σ Γ.N :τ
Γ. < M, N >: σ × τ
Γ.M :σ×τ
Γ . π1 (M) : σ
Γ.M :σ×τ
Γ . π2 (M) : τ
Nuevos casos para el algoritmo de inferencia:
PT (π1 (U)) :
Si la llamada recursiva devuelve PT (U) = Γ . M : σ
Construimos una sustitución que unifique σ con un par genérico s × t, con s y
t variables frescas.
S = Unify{σ =
˙ s ×t }
Finalmente:
PT (π1 (U)) = SΓ . S(π1 (M)) : Ss
El caso de π2 (U) es muy parecido...
Nuevos casos para el algoritmo de inferencia:
PT (< U, V >) :
Si las llamadas recursivas devuelven:
PT (U) = Γ . M : σ
PT (V ) = Γ0 . N : τ
Construimos una sustitución que unifique las variables libres de ambos
contextos:
S = Unify{α=β
˙ | x : α ∈ Γ ∧ x : β ∈ Γ0 }
Finalmente:
PT (< U, V >) = SΓ ∪ SΓ0 . S(< M, N >) : Sσ × Sτ
Para pensar ... (2)
Extender el algoritmo de inferencia visto en clase para que soporte
el tipado de un observador universal (case) de números naturales.
Su sintaxis es la siguiente:
M ::= ... | caseNat M of 0 → N ; Succ(x) → O
y su regla de tipado, la siguiente:
Γ . M : Nat
Γ.N :σ
Γ ∪ {x : Nat} . O : σ
Γ . caseNat M of 0 → N ; Succ(x) → O : σ
Ayuda: observar el parecido en la regla de tipado con un λ y
qué hace el algoritmo en ese caso.
Nuevos casos para el algoritmo de inferencia (2):
PT (caseNat U of 0 → V ; Succ(x) → W ) :
Si las llamadas recursivas devuelven:
PT (U) = Γ1 . M : σ, PT (V ) = Γ2 . N : τ, PT (W ) = Γ3 . O : ρ
Construimos una sustitución que unifique las variables libres de ambos
contextos, unifique los tipos de V y W, y unifique el tipo de U con nat. La
variable x debe tener tipo Nat sólo dentro del contexto de W, debe poder
aparecer libre en cualquier otro lado con otro tipo. Por ejemplo en:
caseNat (λy : Bool.Succ(0))x of 0 → 0 ; Succ(x) → x
S = Unify({τ =ρ}
˙
∪ {σ =Nat}∪
˙
{α=β
˙ | v : α ∈ Γi ∧ v : β ∈ Γj , 1 ≤ i, j ≤ 3, v 6= x}∪
{α=β
˙ | x : α ∈ Γi ∧ x : β ∈ Γj , 1 ≤ i, j ≤ 2})
Finalmente:
PT (caseNat U of 0 → V ; Succ(x) → W ) =
SΓ1 ∪ SΓ2 ∪ S(Γ3 − {x : α}) . S(caseNat M of 0 → N ; Succ(x) → O) : Sρ
Para pensar...(el último):
Asumimos que tenemos la constante polimórfica (==) : s → s,
pero no vale instanciar s en cualquier tipo, sólo vale para algunos.
¿Cómo se agregarı́a la clase de tipos Eq?
Ahora los juicios de tipado ahora son de la forma:
Γ . M : {σ1 , · · · , σm } ⇒ σ
Esto se lee: “M tiene tipo σ bajo contexto Γ si σ1 , · · · , σm tienen
la igualdad (==) definida”.
El axioma de inferencia de == queda ası́:
∅ . ==: {s} ⇒ s → s
Nuevos casos para el algoritmo de inferencia (el último):
El caso importante es el ==:
PT (==)= ∅. ==s : {s} ⇒ s → s, con s variable fresca
Ahora sı́ hay que modificar los casos que ya existı́an:
PT (x) = {x : t} . x : ∅ ⇒ t, siendo t una variable de tipo fresca.
Para las constantes que no son ==, simplemente se agrega el conjunto ∅ al
juicio de tipado.
En general para el resto de los casos, sigue todo igual y se unen los conjuntos
de Eq de los subtérminos y se les aplica la sustitución. Por ejemplo:
PT (UV ) :
PT (U) = Γ . M : {τ1 , · · · , τm } ⇒ τ
PT (V ) = Γ0 . N : {ρ1 , · · · , ρn } ⇒ ρ
S se define igual que antes.
PT (UV ) = SΓ ∪ SΓ0 . S(MN) : S({τ1 , · · · , τm } ∪ {ρ1 , · · · , ρn }) ⇒ St
Fin de la clase
¿?
¿? ¿?
¿?
¿? ¿? ¿? ¿?
¿?
Descargar