Tipos de Polimorfismo
Uma construção que pode assumir diferentes tipos, de acordo com o contexto, é dita polimórfica.
• três formas de polimorfismo em linguagens modernas:
– polimorfismo paramétrico - uma função pode ser
aplicada a qualquer argumento cujo tipo casa com uma expressão de tipos envolvendo variáveis de tipos
– polimorfismo ad-hoc - outro termo para overloading, no qual duas ou mais implementações com tipos
diferentes são referenciadas pelo mesmo nome
– polimorfismo baseado em subtipos - relações entre
Subtipos
• encontrados em linguagens orientadas a objetos
• considerados fundamentais nesse paradigma
• aqui veremos
– idéia básica com registros e funções
– interação com outras contruções: referências – outra semântica para subtipos: inserção de
"coerção"em tempo de execução – subtipagem algoritmica (algoritmo)
– subtipos com polimorfismo paramétrico e com tipos recursivos,
Subtipos - Motivação
• um sistema de tipo é projetado com o objetivo de não
permitir a tentativa de avalição de termo preso, e de termo cuja avaliação eventualmente levaria a termo preso
• mas como estamos considerando verificação estática de
tipos (ou seja em tempo de compilação) certos termos são excluidos mesmo que suas avaliações sejam bem
comportadas
• Exercício: mostre três exemplos de termos não tipados mas
Subtipos - Motivação
O termo (λr : {x : Nat}. r.x) {x = 0, y = 1} não é bem tipado
devido a seguinte regra para aplicação
Γ ⊢ t1 : T → T′ Γ ⊢ t2 : T
Γ ⊢ t1 t2 : T′
(T-APP)
Porém sua avaliação não fica presa em nenhum momento de acordo com as regras da semântica operacional
Subtipos - Motivação
• A função λr : {x : Nat}. r.x só tem um exigência quanto
ao seu argumento: ele deve ser um registro que possua um
campo de nome x e do tipo Nat
• Sempre será seguro passar um argumento do tipo
{x : Nat, y; Nat}, por exemplo, para uma função que
espera argumento do tipo {x : Nat}
• com subtipos, termos bem comportados como
(λr : {x : Nat}. r.x) {x = 0, y = 1} passam a ser bem
Subtipos
• dizemos que o tipo S é subtipo do tipo T , escrito S <: T ,
quando termo do tipo S pode ser utilizado com segurança em algum contexto onde termo do tipo T é esperado
• vimos que registro do tipo {x : Nat, y : Nat} pode ser
usado em contexto que espera registro do tipo {x : Nat},
logo
{x : Nat, y : Nat} <: {x : Nat}
A Relação de Subtipo
• até agora não vimos como determinar quando um tipo é
subtipo de outro
• vamos condições para que um tipo registro seja subtipo de
outro tipo registro e para que um tipo função seja subtipo de outro tipo função
• antes disso, eis duas características da relação <: de subtipo
S <: S (S-REFL)
S <: U U <: T S <: T
Subtipos e Registros
{li : Tii∈1...n+k} <: {li : Tii∈1...n} (S-RCDWIDTH)
Si <: Ti para cada i {li : Si∈1...n} <: {li : Ti∈1...n} (S-RCDDEPTH) {kj : S j∈1...n j } é permutação de {li : T i∈1...n i } {kj : S j∈1...n j } <: {li : T i∈1...n i } (S-RCDPERM)
Subtipos e Funções
• Considere um contexto que espera função do tipo T1 → T2,
como saber se uma função do tipo S1 → S2 pode ser usada
com segurança ?
• ou seja, como deve ser defnida a relação <: para tipos
função?
??
S1 → S2 <: T1 → T2
Subtipos e Funções
• contexto espera função do tipo T1 → T2, isso quer dizer
que:
– função pode receber do contexto argumento do tipo T1
– função, caso seja aplicada a algum argumento,
retornará ao contexto termo do tipo T2
Subtipos e Funções
• para função do tipo S1 → S2 poder ser usada no lugar dessa
função do tipo T1 → T2 duas condições devem ser
observadas
– T1 <: S1, após a troca de função o argumento que
poder vir continuará sendo do tipo T1, mas a nova
função espera argumento do tipo S1
– S2 <: T2, ou seja espera que resultado seja do tipo T2
Subtipos e funções
A regra fica portanto:
T1 <: S1 S2 <: T2
S1 → S2 <: T1 → T2
(S-ARROW)
Subtipos
• a conexão entre a relação de subtipo <: e o sistema de tipos
é dada pela seguinte regra:
Γ ⊢ t : S S <: T Γ ⊢ t : T
(T-SUB)
• Exercício: use o fato acima mais a regra T-Sub e mostre uma derivação de tipos para o termo
Subtipos e Variantes
• As regras de subtipos para variantes são quase idênticas as
regras para registros
• A diferença é que a regra S-VARIANTWIDHT permite
adição (e não remoção) de novos variantes de um subtipo para um supertipo:
< li : Tii∈1...n > <: < li : Tii∈1...n+k >
(S-VARIANT-WIDTH)
• Por que?
Subtipos e Variantes
• Combinando variantes com subtipos não é necessário
escrever anotação de tipo < l = t > as < li : Tii∈1...n >,
basta escrever < l = t >
Listas
Tipo List T descreve lista de tamanho finito cujos elementos são do tipo T
• a lista vazia (de elementos do tipo T ) é escrita nil[T]
• a lista formada adicionando elemento t1, do tipo T , em
fronte da lista t2 é escrita cons[T] t1 t2
• a cabeça e a cauda de uma lista t são escritas head[T] t e
tail[T] t respectivamente
• o termo isnil[T] t retorna true se a lista t for vazia
Listas
Exercícios:
1. defina sintaxe, semântica operacional e regras de tipos para listas
2. verifique se progresso e preservação de tipos são
Listas e Subtipos
• o contrutor de tipos List é covariante:
S <: T
List S <: List T
(S-LIST)
Referências
• Nem todo construtor de tipos é covariante ou contravariante
• o construtor ref por exemplo, é invariante para garantir
segurança do sistema de tipos:
• Um valor do tipo ref T pode ser usado em duas situações:
para leitura e para escrita
• Usado para leitura: contexto espera obter valor do tipo T ,
mas se a leitura traz um valor do tipo S então é preciso que
S <: T
• Usado para escrita: valor fornecido pelo contexto é do tipo
T . Se o tipo da referência for ref S então alguém mais
tarde pode ler esse valor e usá-lo comose fosse do tipo S