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!
function f(a): forall t: Type, t->t
function g(a): forall t: Type, t->t
return (a is g) ? f : a
return a is f ? g : a
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ções f
e g
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, porque f(f)
retorna g
, enquanto a identidade retornaria f
.
Para que o teorema se mantenha, ele deve assumir a capacidade ridícula de reduzir
function cantor(n, <z, a>) : forall t: t: Type int, <int, t> -> <int, t>
return n > 1 ? cantor((n % 2 > 0) ? (n + 1) : n / 2, <z + 1, a>) : <z, a>
return cantor(1000, <0, a>)[1]¹
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.
- Funcional puro (sem estado mutável, sem IO). OK, eu posso viver com isso. Muito tempo queremos executar provas sobre funções.
- Biblioteca padrão vazia. meh.
- Não
raise
e não exit
. Agora estamos começando a ficar constrangidos.
- Não há tipo de fundo.
- O idioma possui uma regra que permite ao compilador recolher recursões infinitas, assumindo que ele deve terminar. É permitido ao compilador rejeitar a recursão infinita trivial.
- É permitido ao compilador falhar se for apresentado algo que não possa ser provado de nenhuma maneira .² Agora a biblioteca padrão não pode aceitar funções como argumentos. Vaia.
- Não existe
nil
. Isso está começando a ficar problemático. Ficamos sem maneiras de lidar com 1 / 0.³
- O idioma não pode fazer inferências de tipo de ramificação e não possui uma substituição para quando o programador puder provar uma inferência de tipo que o idioma não pode. Isso é muito ruim.
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
function fermat(z) : int -> int
function pow(x, p)
return p = 0 ? 1 : x * pow(x, p - 1)
function f2(x, y, z) : int, int, int -> <int, int>
left = pow(x, 5) + pow(y, 5)
right = pow(z, 5)
return left = right
? <x, y>
: pow(x, 5) < right
? f2(x + 1, y, z)
: pow(y, 5) < right
? f2(2, y + 1, z)
: f2(2, 2, z + 1)
return f2(2, 2, z)
function cantor(n, <z, a>) : forall t: t: Type int, <int, t> -> <int, t>
return n > 1 ? cantor((n % 2 > 0) ? (n + 1) : n / 2, <z + 1, a>) : <z, a>
return cantor(fermat(3)[0], <0, a>)[1]
² 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.
function f(a, b, c): t: Type: t[],int,int->t
return a[b/c]
não deve compilar. O problema fundamental é que a indexação de array em tempo de execução não funciona mais.