Eu sou novo em teoria da linguagem de programação. Eu estava assistindo algumas palestras on-line nas quais o instrutor alegava que uma função com tipo polimórfico forall t: Type, t->t
seria a identidade, mas não explicava o porquê. Alguém pode me explicar por quê? Talvez uma prova da reivindicação dos primeiros princípios.
programming-languages
type-theory
abhishek
fonte
fonte
Respostas:
A primeira coisa a observar é que isso não é necessariamente verdade. Por exemplo, dependendo do idioma, uma função com esse tipo, além de ser a função de identidade, poderia: 1) loop para sempre, 2) alterar algum estado, 3) retornar
null
, 4) lançar uma exceção, 5) executar alguma E / S, 6) bifurque um thread para fazer outra coisa, 7) façacall/cc
travessuras, 8) use algo como JavaObject.hashCode
, 9) use reflexão para determinar se o tipo é um número inteiro e, se necessário, incremente-o, 10) use reflexão para analisar a pilha de chamadas e faça algo com base no contexto em que é chamado, 11) provavelmente muitas outras coisas e certamente combinações arbitrárias das anteriores.Portanto, a propriedade que leva a isso, a parametridade, é uma propriedade da linguagem como um todo e existem variações mais fortes e mais fracas dela. Para muitos dos cálculos formais estudados na teoria dos tipos, nenhum dos comportamentos acima pode ocorrer. Por exemplo, para o Sistema F / cálculo lambda polimórfico puro, onde a parametridade foi estudada pela primeira vez, nenhum dos comportamentos acima pode ocorrer. Ele simplesmente não tem exceções, estado mutável,
null
,call/cc
, I / O, reflexão, e é normalizar fortemente para que ele não pode fazer um loop para sempre. Como Gilles mencionou em um comentário, o jornal Theorems for free!por Phil Wadler é uma boa introdução a esse tópico e suas referências serão mais aprofundadas na teoria, especificamente na técnica das relações lógicas. Esse link também lista alguns outros trabalhos de Wadler sobre o tema da parametridade.Como a parametridade é uma propriedade da linguagem, para provar isso, é necessário primeiro articular formalmente a linguagem e depois um argumento relativamente complicado. O argumento informal para este caso em particular, assumindo que estamos no cálculo lambda polimórfico, é que, como não sabemos nada sobre
t
, não podemos executar nenhuma operação na entrada (por exemplo, não podemos incrementá-la porque não sabemos se é um número) ou crie um valor desse tipo (pelo que sabemost
=Void
, um tipo sem nenhum valor). A única maneira de produzir um valor do tipot
é retornar o que é dado a nós. Nenhum outro comportamento é possível. Uma maneira de ver isso é usar forte normalização e mostrar que existe apenas um termo de forma normal desse tipo.fonte
A prova da alegação é bastante complexa, mas se é isso que você realmente deseja, pode conferir o artigo original de Reynolds sobre o assunto.
A idéia principal é que ele se aplica a funções parametricamente polimórficas , em que o corpo de uma função polimórfica é o mesmo para todas as instanciações monomórficas da função. Nesse sistema, nenhuma suposição pode ser feita sobre o tipo de parâmetro do tipo polimórfico e, se o único valor no escopo tiver um tipo genérico, não há nada a ver com isso, mas devolvê-lo ou passá-lo para outras funções que você ' definido, que por sua vez não pode fazer nada além de devolvê-lo ou passá-lo ... etc. Portanto, no final, tudo o que você pode fazer é alguma cadeia de funções de identidade antes de retornar o parâmetro.
fonte
Com todas as ressalvas mencionadas por Derek e ignorando os paradoxos resultantes do uso da teoria dos conjuntos, deixe-me esboçar uma prova no espírito de Reynolds / Wadler.
Uma função do tipo:
é uma família de funções indexados por tipo .ft t
A idéia é que, para definir formalmente funções polimórficas, não devemos tratar tipos como conjuntos de valores, mas como relações. Tipos básicos, como
Int
induzir relações de igualdade - por exemplo, doisInt
valores são relacionados se forem iguais. As funções são relacionadas se mapearem valores relacionados para valores relacionados. O caso interessante são as funções polimórficas. Eles mapeiam tipos relacionados para valores relacionados.No nosso caso, queremos estabelecer uma relação entre duas funções polimórficas e do tipo:f g
Suponha que o tipo esteja relacionado ao tipo . A primeira função mapeia os tipos para um valor - aqui, o próprio valor é uma função do tipo . A segunda função mapeia o tipo para outro valor do tipo . Dizemos que está relacionado com se os valores e estão relacionados. Como esses valores são funções, eles são relacionados se mapearem valores relacionados a valores relacionados.s t f s fs s → s t gt t → t f g fs gt
O passo crucial é usar o teorema da parametridade de Reynolds, que diz que qualquer termo está relacionado com ele. No nosso caso, a funçãofs ft
f
está relacionada a si mesma. Em outras palavras, ses
estiver relacionado at
, também estará relacionado a .Agora podemos escolher qualquer relação entre dois tipos e aplicar esse teorema. Vamos escolher o primeiro tipo como o tipo de unidadef() ft f() ft deve mapear ft eu dt
()
, que possui apenas um valor, também chamado()
. Manteremos o segundo tipot
arbitrário, mas não vazio. Vamos escolher uma relação entre()
et
para ser simplesmente um par((), c)
, ondec
há algum valor do tipot
(uma relação é apenas um subconjunto do produto cartesiano de conjuntos). O teorema da parametridade nos diz que deve estar relacionado a . Eles devem mapear valores relacionados para valores relacionados. A primeira função não tem muita escolha, deve mapear o único valor para . Portanto, a segunda função()
()
c
parac
(os únicos valores relacionados a()
). Desdec
é completamente arbitrária, concluímos que é e, uma vez que é completamente arbitrária, é .t
f
id
Você pode encontrar mais detalhes no meu blog .
fonte
EDIT: Um comentário acima forneceu a peça que faltava. Algumas pessoas brincam deliberadamente com idiomas completos que não são turing. Eu explicitamente não me importo com esses idiomas. Uma linguagem realmente comum, não turing-complete, é uma coisa louca e difícil de projetar. O resto disso se expande sobre o que acontece tentando aplicar esses teoremas a uma linguagem completa.
Falso!
onde o
is
operador compara duas variáveis para a identidade de referência. Ou seja, eles contêm o mesmo valor. Não é um valor equivalente, mesmo valor. Funçõesf
eg
são equivalentes por alguma definição, mas não são iguais.Se essa função é aprovada, ela retorna outra coisa; caso contrário, ele retorna sua entrada. A outra coisa tem o mesmo tipo que ela mesma, portanto, pode ser substituída. Em outras palavras,
f
não é a identidade, porquef(f)
retornag
, enquanto a identidade retornariaf
.Para que o teorema se mantenha, ele deve assumir a capacidade ridícula de reduzir
Se você estiver disposto a assumir que pode assumir a inferência de tipo muito mais fácil, pode ser manipulada.
Se tentarmos restringir o domínio até que o teorema se mantenha, acabamos tendo que restringi-lo terrivelmente.
raise
e nãoexit
. Agora estamos começando a ficar constrangidos.nil
. Isso está começando a ficar problemático. Ficamos sem maneiras de lidar com 1 / 0.³A existência das duas últimas restrições prejudicou a linguagem. Enquanto Turing ainda está completo, a única maneira de obter um trabalho de propósito geral é simular uma plataforma interna que interpreta um idioma com requisitos mais flexíveis.
¹ Se você acha que o compilador pode deduzir esse, tente este
² A prova de que o compilador não pode fazer isso depende de ofuscamento. Podemos usar várias bibliotecas para garantir que o compilador não possa ver o loop de uma só vez. Além disso, sempre podemos construir algo em que o programa funcionaria, mas não pôde ser compilado porque o compilador não pode executar a indução na memória disponível.
³ Alguém pensa que você pode ter esse retorno nulo sem que tipos genéricos arbitrários retornem nulo. Isso paga uma penalidade desagradável pela qual não vi uma linguagem eficaz que possa pagá-la.
não deve compilar. O problema fundamental é que a indexação de array em tempo de execução não funciona mais.
fonte
foil
quantificador, afinal?) Isso não ajuda em nada.