Sí, es posible expresar un tipo preciso para una rutina de clasificación, de modo que cualquier función que tenga ese tipo debe ordenar la lista de entrada.
Si bien puede haber una solución más avanzada y elegante, esbozaré una solución primaria, solo.
f: nat -> nat
0 .. n - 1
Definition permutation (n: nat) (f: nat -> nat): Prop :=
(* once restricted, its codomain is 0..n-1 *)
(forall m, m < n -> f m < n) /\
(* it is injective, hence surjective *)
(forall m1 m2, m1 < n -> m2 < n -> f m1 = f m2 -> m1 = m2) .
Un simple lema puede ser fácilmente probado.
Lemma lem1: forall n f, permutation n f -> m < n -> f m < n.
... (* from the def *)
metronorteh
m < n
Definition nth {A} {n} (l: list A n) m (h : m < n): A :=
... (* recursion over n *)
Dado un pedido A
, podemos expresar que una lista está ordenada:
Definition ordering (A: Type) :=
{ leq: A->A->bool |
(* axioms for ordering *)
(forall a, leq a a = true) /\
(forall a b c, leq a b = true -> leq b c = true -> leq a c = true) /\
(forall a b, leq a b = true -> leq b a = true -> a = b)
} .
Definition sorted {A} {n} (o: ordering A) (l: list A n): Prop :=
...
Finalmente, aquí está el tipo para un algoritmo de clasificación:
Definition mysort (A: Type) (o: ordering A) (n: nat) (l: list A n):
{s: list A n | sorted o s /\
exists f (p: permutation n f),
forall (m: nat) (h: m < n),
nth l m h = nth s (f m) (lem1 n f p h) } :=
... (* the sorting algorithm, and a certificate for its output *)
s
norte0 .. n - 1l
s
F( m ) < nnth
Sin embargo, tenga en cuenta que es el usuario, es decir, el programador, el que tiene que demostrar que su algoritmo de clasificación es correcto. El compilador no solo verificará que la clasificación sea correcta: todo lo que hace es verificar una prueba provista. De hecho, el compilador no puede hacer mucho más que eso: las propiedades semánticas como "este programa es un algoritmo de clasificación" son indecidibles (por el teorema de Rice), por lo que no podemos esperar que el paso de prueba sea completamente automático.
En el futuro lejano, aún podemos esperar que los probadores de teoremas automáticos se vuelvan tan inteligentes que "la mayoría" de los algoritmos utilizados en la práctica puedan probarse automáticamente como correctos. El teorema de Rice solo establece que esto no se puede hacer en todos los casos. Todo lo que podemos esperar es un sistema correcto, ampliamente aplicable, pero inherentemente incompleto.
Como nota final, a veces se olvida que incluso los sistemas de tipos simples están incompletos . Por ejemplo, incluso en Java
int f(int x) {
if (x+2 != 2+x)
return "Houston, we have a problem!";
return 42;
}
es semánticamente seguro de tipo (siempre devuelve un número entero), pero el verificador de tipo se quejará del retorno inalcanzable.