Да, для процедуры сортировки можно выразить точный тип, так что любая функция, имеющая этот тип, должна действительно сортировать список ввода.
Хотя может быть более продвинутое и изящное решение, я нарисую только простое.
Мы будем использовать Coq-подобные обозначения. Мы начнем с определения предиката, требующего, чтобы он 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) .
Простая лемма легко доказывается.
Lemma lem1: forall n f, permutation n f -> m < n -> f m < n.
... (* from the def *)
Мы определяем, какой й элемент списка имеет длину . Эта функция требует доказательства того , что действительно выполняется.мNh
м < н
Definition nth {A} {n} (l: list A n) m (h : m < n): A :=
... (* recursion over n *)
Учитывая порядок A
, мы можем выразить, что список отсортирован:
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 :=
...
Наконец, вот тип для алгоритма сортировки:
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
N0 .. n - 1l
s
е( м ) < пnth
Обратите внимание, что именно пользователь, то есть программист, должен доказать правильность алгоритма сортировки. Компилятор не просто проверит правильность сортировки: он лишь проверяет предоставленное доказательство. Действительно, компилятор не может сделать намного больше: семантические свойства, такие как «эта программа является алгоритмом сортировки», неразрешимы (по теореме Райса), поэтому мы не можем надеяться сделать шаг проверки полностью автоматическим.
В далеком, далеком будущем мы все еще можем надеяться, что автоматические средства проверки теорем станут настолько умными, что «большинство» практически используемых алгоритмов могут быть автоматически доказаны правильными. Теорема Райса только утверждает, что это не может быть сделано во всех случаях. Все, на что мы можем надеяться, - это правильная, широко применимая, но изначально неполная система.
И последнее замечание: иногда забывают, что даже простые системы типов неполны ! Например, даже на Яве
int f(int x) {
if (x+2 != 2+x)
return "Houston, we have a problem!";
return 42;
}
является семантически безопасным типом (он всегда возвращает целое число), но средство проверки типов будет жаловаться на недостижимый возврат.