Có, có thể biểu thị một loại chính xác cho một thói quen sắp xếp, sao cho bất kỳ hàm nào có loại đó thực sự phải sắp xếp danh sách đầu vào.
Mặc dù có thể có một giải pháp tiên tiến và thanh lịch hơn, nhưng tôi sẽ chỉ phác thảo một giải pháp cơ bản.
Chúng tôi sẽ sử dụng một ký hiệu giống như Coq. Chúng tôi bắt đầu bằng cách xác định một vị từ yêu cầu f: nat -> nat
hoạt động như một hoán vị trên :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) .
Một bổ đề đơn giản có thể dễ dàng được chứng minh.
Lemma lem1: forall n f, permutation n f -> m < n -> f m < n.
... (* from the def *)
Chúng tôi xác định phần tử thứ của danh sách có độ dài . Hàm này yêu cầu một bằng chứng cho biết thực sự nắm giữ.mnh
m<n
Definition nth {A} {n} (l: list A n) m (h : m < n): A :=
... (* recursion over n *)
Đưa ra một đơn đặt hàng trên A
, chúng tôi có thể thể hiện rằng một danh sách được sắp xếp:
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 :=
...
Cuối cùng, đây là loại cho một thuật toán sắp xếp:
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 *)
Các trạng thái loại ra rằng danh sách kết quả s
là yếu tố dài, nó được sắp xếp, và rằng có một hoán vị của mà các bản đồ các yếu tố trong danh sách đầu vào để những người trong danh sách kết quả . Lưu ý rằng chúng ta phải gọi bổ đề ở trên để chứng minh , được yêu cầu bởi .n0..n−1l
s
f(m)<nnth
Tuy nhiên, lưu ý rằng đó là người dùng, tức là người lập trình, phải chứng minh thuật toán sắp xếp của họ đúng. Trình biên dịch sẽ không chỉ đơn giản xác minh rằng việc sắp xếp là chính xác: tất cả những gì nó làm là kiểm tra một bằng chứng được cung cấp. Thật vậy, trình biên dịch không thể làm được nhiều hơn thế: các thuộc tính ngữ nghĩa như "chương trình này là một thuật toán sắp xếp" là không thể giải quyết được (theo định lý Rice), vì vậy chúng tôi không thể hy vọng làm cho bước chứng minh hoàn toàn tự động.
Trong tương lai xa, chúng ta vẫn có thể hy vọng rằng các trình tiên đoán định lý tự động trở nên thông minh đến mức các thuật toán được sử dụng thực tế nhất có thể được chứng minh là chính xác. Định lý Rice chỉ nói rằng điều này không thể được thực hiện trong mọi trường hợp. Tất cả những gì chúng ta có thể hy vọng là một hệ thống chính xác, áp dụng rộng rãi, nhưng vốn không hoàn chỉnh.
Như một lưu ý cuối cùng, đôi khi người ta quên rằng ngay cả các hệ thống loại đơn giản cũng không đầy đủ ! Ví dụ: ngay cả trong Java
int f(int x) {
if (x+2 != 2+x)
return "Houston, we have a problem!";
return 42;
}
là loại ngữ nghĩa an toàn (nó luôn trả về một số nguyên), nhưng trình kiểm tra loại sẽ phàn nàn về lợi nhuận không thể truy cập.