EDITAR: Un comentario anterior ha proporcionado la pieza que falta. Algunas personas están jugando deliberadamente con idiomas menos completos. Explícitamente no me importan esos lenguajes. Un lenguaje realmente útil que no sea completo es una locura difícil de diseñar. Todo lo demás se expande sobre lo que sucede tratando de aplicar estos teoremas a un lenguaje completo.
¡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
donde el is
operador compara dos variables para la identidad de referencia. Es decir, contienen el mismo valor. No es un valor equivalente, el mismo valor. Funciones f
y g
son equivalentes por alguna definición, pero no son lo mismo.
Si esta función se pasa a sí misma, devuelve algo más; de lo contrario, devuelve su entrada. El algo más tiene el mismo tipo que sí mismo, por lo tanto, puede ser sustituido. En otras palabras, f
no es la identidad, porquef(f)
regresa g
, mientras que la identidad volvería f
.
Para que el teorema se mantenga tiene que asumir la capacidad ridícula de reducir
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]¹
Si está dispuesto a asumir que puede asumir que se puede manejar la inferencia de tipos mucho más fácil.
Si tratamos de restringir el dominio hasta que se mantenga el teorema, terminamos teniendo que restringirlo terriblemente lejos.
- Funcional puro (sin estado mutable, sin IO). OK, puedo vivir con eso. Muchas veces queremos ejecutar pruebas sobre funciones.
- Biblioteca estándar vacía. meh
- No
raise
y no exit
. Ahora estamos empezando a estar limitados.
- No hay tipo de fondo.
- El lenguaje tiene una regla que permite al compilador colapsar la recursión infinita suponiendo que debe terminar. El compilador puede rechazar la recursividad trivial infinita.
- El compilador puede fallar si se le presenta algo que no se puede probar de ninguna manera .² Ahora la biblioteca estándar no puede tomar funciones como argumentos. Abucheo.
- No existe
nil
. Esto está empezando a ser problemático. Nos hemos quedado sin formas de lidiar con 1 / 0.³
- El lenguaje no puede hacer inferencias de tipo de rama y no tiene una anulación para cuando el programador puede probar una inferencia de tipo que el idioma no puede. Esto es muy malo
La existencia de las dos últimas restricciones ha paralizado el lenguaje. Si bien aún está completando Turing, la única forma de obtener un trabajo de propósito general es simular una plataforma interna que interprete un lenguaje con requisitos más flexibles.
¹ Si crees que el compilador puede deducir ese, prueba 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]
² La prueba de que el compilador no puede hacer esto depende del cegamiento. Podemos usar varias bibliotecas para asegurarnos de que el compilador no pueda ver el ciclo a la vez. Además, siempre podemos construir algo donde el programa funcionaría pero no podría compilarse porque el compilador no puede realizar la inducción en la memoria disponible.
³ Alguien piensa que puede devolver este valor nulo sin que los tipos genéricos arbitrarios devuelvan nulo. Esto paga una penalidad desagradable por la cual no he visto un lenguaje efectivo que pueda pagarlo.
function f(a, b, c): t: Type: t[],int,int->t
return a[b/c]
No debe compilar. El problema fundamental es que la indexación de la matriz en tiempo de ejecución ya no funciona.