Cálculo lambda simplesmente tipado
O cálculo lambda simplesmente tipado (), ou cálculo lambda com tipagem simples, é um modelo da teoria dos tipos que adiciona o conceito de tipagem ao cálculo lambda. Isso é possível com adição de apenas um elemento (o construtor de tipos: ) para construir tipos de funções. Esse é o exemplo mais simples e canônico de um cálculo lambda com tipagem. O cálculo lambda simplesmente tipado foi introduzido originalmente por Alonzo Church em 1940 como uma tentativa de evitar o uso paradoxal do lambda cálculo não tipado, o qual mostrou várias propriedades interessantes e desejadas.
O termo tipo simples também é utilizado para se referir à extensões do cálculo lambda simplesmente tipado como produtos, coprodutos, números naturais (Sistema T) ou até recursão completa. Em contraste, sistemas que introduzem tipos polimórficos (como o Sistema F) ou tipos dependentes não são considerados simplesmente tipados. O cálculo lambda simplesmente tipado é considerado simples por conta da Codificação de Church de suas estruturas que pode ser feita usando apenas o símbolo e variáveis de tipos adequadas, enquanto polimorfismo e dependência não podem.
Sintaxe
[editar | editar código-fonte]Para definir os tipos, começa-se determinando um conjunto de tipos base, . Esses tipos são chamados tipos atômicos ou constantes de tipos. Tendo-os determinado, a sintaxe dos tipos pode ser exemplificada da seguinte forma:
.
Neste artigo serão utilizados e para representação dos tipos. Informalmente, o tipo de função se refere a um conjunto de funções que, dado uma entrada do tipo , produz uma saída do tipo . Por convenção, associa à direita, ou seja, é lido como .
Os termos constantes também são fixos para os tipos base. Por exemplo, assume-se que o tipo base nat, e as constantes de termo podem ser os números naturais. Na representação original, Church utilizou apenas dois tipos base: para os tipos de proposições e para os tipos de indivíduos. O tipo não contém constantes de termo, enquanto que contém uma constante de termo. Frequentemente apenas o cálculo com um tipo base é considerado (normalmente ).
A sintaxe do cálculo lambda simplesmente tipado é essencialmente a mesma do cálculo lambda. A sintaxe dos termos utilizados neste artigo é mostrada a seguir:
onde é uma constante de termo.
Isto é, variável de referência, abstrações, aplicação e constante. A variável de referência é ligada se estiver dentro de uma abstração ligando . Um termo é fechado se não existir variáveis não ligadas.
Compare com a sintaxe do cálculo lambda não tipado:
É possível verificar que no cálculo lambda tipado toda função (abstração) deve especificar o tipo de seus argumentos.
Regras de tipagem
[editar | editar código-fonte]Para definir o conjunto de lambda termos bem tipados para um dado tipo é necessário definir a relação de tipagem entre termos e tipos. Primeiro será introduzido os contextos de tipagem , que são conjuntos de suposições de tipagem. Uma suposição de tipagem tem forma , que significa tem tipo .
A relação de tipagem indica que é um termo do tipo no contexto . Isto é o mesmo que dizer que " é bem-tipado (em )". Instâncias de uma relação de tipagem são chamadas sentenças de tipagem. A validade de uma sentença de tipagem é mostrada provando-se a derivação de tipagem, construída usando as seguintes regras de tipagem (em que as premissas acima da linha permitem derivar a conclusão abaixo da linha):
(1) (2) |
(3) (4) |
Em outras palavras,
- Se tem tipo no contexto, sabe-se que tem tipo .
- Constantes de termos tem o tipo base apropriado.
- Se, em um determinado contexto com tendo tipo , tem tipo , então, no mesmo contexto sem , tem tipo .
- Se, em um determinado contexto, tem tipo , e tem tipo , então tem tipo .
Exemplos de termos fechados, isto é termos tipáveis em um contexto vazio:
- Para todo tipo , um termo (o combinador I/função identidade),
- Para tipos , um termo (o combinador K), e
- Para tipos , um termo (o combinador S).
Essas são as representações no lambda cálculo tipado dos combinadores básicos da lógica combinatória.
Para cada tipo é atribuído uma ordem, um número . Para os tipos base, ; para tipos de função, . Isto é, a ordem de um tipo mede a profundidade da seta aninhada mais à esquerda. Logo:
Semântica
[editar | editar código-fonte]Estilo Church vs estilo Curry
[editar | editar código-fonte]De um modo geral, existem duas maneiras de atribuição de significado para o cálculo lambda simplesmente tipado, às vezes chamado intrínseco vs extrínseco, ou estilo Church vs. estilo Curry.[1] Uma semântica estilo Church apenas atribui significado à termos bem tipados, ou mais precisamente, atribui significado diretamente por derivações de tipagem. O efeito disso é que é possível se atribuir significados diferentes à termos que se diferenciam apenas por anotações de tipos. Por exemplo, o termo identidade nos inteiros () e o termo identidade nos booleanos () podem significar coisas diferentes. Entretanto, uma semântica estilo Curry atribui significado para termos independente da tipagem, como seriam interpretados em uma linguagem não tipada. Nesta visão, e significam a mesma coisa (isto é, ).
A distinção entre semântica intrínseca e extrínseca é às vezes associada a presença ou não de anotações nas abstrações lambda, mas estritamente falando esse uso é impreciso. É possível se definir uma semântica estilo Curry em termos anotados simplesmente ignorando os tipos (através da remoção de tipos, como também é possível prover uma semântica estilo Church a termos não anotados quando os tipos podem ser deduzidos do contexto (através da inferência de tipos). A diferença essencial entre essas duas abordagens é apenas como as regras de tipagem são vistas na definição da linguagem, ou como um formalismo para verificação de propriedades de uma linguagem fundamental mais primitiva. Maior parte da diferença das interpretações semânticas discutidas abaixo podem ser vistas sob uma ótica Church ou Curry.
Teoria equational
[editar | editar código-fonte]O cálculo lambda simplesmente tipado tem a mesma teoria da -equivalência do cálculo lambda não tipado, mas sujeito à retrições de tipos. A equação é verdadeira em um contexto sempre que e , enquanto a equação é verdadeira sempre que .
Semântica operacional
[editar | editar código-fonte]De modo semelhante, a semântica operacional do cálculo lambda simplesmente tipado pode ser determinada como a do cálculo lambda não tipado, utilizando-se chamada por valor, ou outra estratégia de avaliação. Assim como para qualquer linguagem tipada, segurança de tipos é uma propriedade fundamental para todas essas estratégias de avaliação. Adicionalmente, a propriedade da normalização forte implica que qualquer estratégia de avaliação irá terminar em todos os termos simplesmente tipados.
Semântica categórica
[editar | editar código-fonte]O cálculo lambda simplesmente tipado (com -equivalência) é a linguagem interna da Categoria Cartesiano Fechado (CCCs), como foi observado primeiro por Joachim Lambek.
Semântica prova-teórica
[editar | editar código-fonte]O cálculo lambda simplesmente tipado é intimamente relacionado ao fragmento implicacional da lógica intuicionista proposicional (lógica minimal) através do Isomorfismo de Curry-Howard: termos correspondem precisamente à provas em dedução natural.
Sintaxes alternativas
[editar | editar código-fonte]A representação utilizada acima não é a única forma de se definir a sintaxe do cálculo lambda simplesmente tipado. Uma das alternativas é remover as anotações de tipo completamente (dessa forma, a sintaxe é idêntica à do cálculo lambda não tipado), garantindo que os termos são bem tipados pela inferência de tipos de Hindley-Milter. O algoritmo de inferência termina, é seguro e completo: sempre que um termo for tipável, o algoritmo computará seu tipo. Mais precisamente, o algoritmo computa o tipo principal do termo, uma vez que frequentemente um termo não anotado (como ) pode ter mais de um tipo (, , etc., sendo todos esses instâncias do tipo principal ).
Outra representação alternativa do cálculo lambda simplesmente tipado é baseada na checagem de tipos bidirecional, que requer mais anotações de tipos que a inferência de Hindley-Milner mas é mais fácil de descrever. O sistema de tipos é dividido em duas sentenças, uma representando a checagem e a outra a síntese, sendo e , respectivamente. Operacionalmente, os três componentes , , e são todos entradas para a sentença de checagem , enquanto a sentença de síntese toma apenas e como entradas, produzindo o tipo como saída. Essas sentenças são derivadas pelas seguintes regras:
[1] [2] |
[3] [4] |
[5] [6] |
Observe que as regras [1]-[4] são praticamente idênticas às regras (1)-(4) acima, exceto pela cautelosa escolha das sentenças de checagem e síntese. Essas escolhas podem ser explicadas da seguinte forma:
- Se está no contexto, pode-se sintetizar o tipo para .
- Os tipos das constantes de termos são fixos e podem ser sintetizados.
- Para checar que tem tipo em algum contexto, pode-se estender o contexto com e checar que tem o tipo .
- Se sintetiza o tipo (em algum contexto), e e se verifica contra o tipo (em algum contexto), então sintetiza o tipo .
Observe que as regras para síntese são lidas de cima para baixo, enquanto as regras para checagem são lidas de baixo para cima. Note em particular que não é necessário qualquer anotação na abstração lambda na regra [3], porque o tipo da variável ligada pode ser deduzido através do tipo que é checado da função. Finalmente, as regras [5] e [6] podem ser explicadas da seguinte forma:
- Para checar que tem tipo , é suficiente para sintetizar o tipo .
- Se verifica-se contra o tipo , então o termo explicitamente anotado sintetiza .
Por conta dessas duas últimas regras coagindo entre síntese e checagem, é fácil perceber que qualquer termo bem tipado mas não anotado pode ser checado no sistema bidirecional, enquanto se puder inserir anotações de tipos "suficientes". E de fato, anotações são necessárias apenas para redexes .
Observações gerais
[editar | editar código-fonte]Dadas as semânticas padrões, o cálculo lambda simplesmente tipado é fortemente normalizável: isto é, termos bem tipados sempre reduzem para um valor (uma abstração ). Isso acontece porque recursão não é permitida pelas regras de tipagem: é impossível encontrar tipos para combinadores de ponto fixo e termos de looping como por exemplo . Recursão pode ser adicionada à linguagem tendo um operador especial do tipo ou adicionando tipos recursivos gerais, porém ambos eliminam a normalização forte.
Resultados importantes
[editar | editar código-fonte]- Tait mostrou em 1967 que a redução é fortemente normalizável. Como corolário a equivalência é decidível. Statman mostrou em 1977 que o problema da normalização não é recursivo elementar.
- O problema da unificação para equivalência é indecidível. Huet mostrou em 1973 que a unificação de terceira ordem é indecidível e isso foi melhorado posteriormente por Baxter em 1978 e depois por Goldfarb em 1981 mostrando que a unificação de segunda ordem é indecidível. Enquanto a correspondência de alta ordem (unificações onde apenas um termo contém variáveis existenciais) é decidível e ainda em aberto. [2006: Colin Stirling, Edinburgh, publicou um esboço da prova que ele alega que o problema é decidível; entretanto, a versão completa da prova ainda não foi publicada]
- É possível codificar números naturais por termos do tipo (numerais de Church). Schwichtenberg mostrou em 1976 que em exatamente os polinômios estendidos são representáveis como funções sobre os numerais de Church; esses são grosseiramente os polinômios fechados sobre o operador condicional.
Notas
[editar | editar código-fonte]- ↑ Reynolds, John (1998). Theories of Programming Languages. Cambridge, England: Cambridge University Press
Referências
[editar | editar código-fonte]- A. Church: A Formulation of the Simple Theory of Types, JSL 5, 1940
- W.W.Tait: Intensional Interpretations of Functionals of Finite Type I, JSL 32(2), 1967
- G.D. Plotkin: Lambda-definability and logical relations, Technical report, 1973
- G.P. Huet: The Undecidability of Unification in Third Order Logic Information and Control 22(3): 257-267 (1973)
- H. Friedman: Equality between functionals. LogicColl. '73, pages 22-37, LNM 453, 1975.
- H. Schwichtenberg: Functions definable in the simply-typed lambda calculus, Arch. Math Logik 17 (1976) 113-114.
- R. Statman: The Typed lambda-Calculus Is not Elementary Recursive FOCS 1977: 90-94
- W. D. Goldfarb: The undecidability of the 2nd order unification problem, TCS (1981), no. 13, 225- 230.
- R. Statman. -definable functionals and conversion. Arch. Math. Logik, 23:21--26, 1983.
- J. Lambek: Cartesian Closed Categories and Typed Lambda-calculi. Combinators and Functional Programming Languages 1985: 136-175
- U. Berger, H. Schwichtenberg: An Inverse of the Evaluation Functional for Typed lambda-calculus LICS 1991: 203-211
- Jung, A.,Tiuryn, J.:A New Characterization of Lambda Definability, TLCA 1993
- R. Loader: The Undecidability of λ-definability, appeared in the Church Festschrift, 2001
- H. Barendregt, Lambda Calculi with Types, Handbook of Logic in Computer Science, Volume II, Oxford University Press, 1993. ISBN 0-19-853761-1.
- L. Baxter: The undecidability of the third order dyadic unification problem, Information and Control 38(2), 170-178 (1978)
Ver também
[editar | editar código-fonte]Ligações externas
[editar | editar código-fonte]- Loader, Ralph (1998). «Notes on Simply Typed Lambda Calculus»