Provare un'operazione di ordinamento nel sistema di tipi


9

Voglio sapere fino a che punto un sistema di tipi in un linguaggio di programmazione può essere utile. Ad esempio, so che in un linguaggio di programmazione tipicamente dipendente, possiamo creare una Vectorclasse che incorpora la dimensione del vettore nella firma del tipo. È come un esempio di fatto. Possiamo anche scrivere una funzione appendusando quelle firme in modo che il compilatore dimostri che la dimensione dell'elenco risultante sarà la somma degli elenchi di input.

Esiste un modo per codificare, ad esempio, nella firma del tipo di un algoritmo di ordinamento in modo che il compilatore garantisca che l'elenco risultante sia una permutazione dell'elenco di input? Come può essere fatto, se è possibile?

Risposte:


13

Sì, è possibile esprimere un tipo preciso per una routine di ordinamento, in modo tale che qualsiasi funzione con quel tipo debba effettivamente ordinare l'elenco di input.

Mentre potrebbe esserci una soluzione più avanzata ed elegante, ne disegnerò solo una elementare.

Useremo una notazione simile a Coq. Iniziamo definendo un predicato che richiede che f: nat -> natfunge da permutazione su :0..n1

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 semplice lemma può essere facilmente dimostrato.

Lemma lem1: forall n f, permutation n f -> m < n -> f m < n.
... (* from the def *)

Definiamo qual è il esimo elemento di un elenco avente lunghezza . Questa funzione richiede una dimostrazione che effettivamente detiene.n m < nmnhm<n

Definition nth {A} {n} (l: list A n) m (h : m < n): A :=
... (* recursion over n *)

Dato un ordine su A, possiamo esprimere che un elenco è ordinato:

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 :=
...

Infine ecco il tipo per un algoritmo di ordinamento:

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 *)

Il tipo di output afferma che l'elenco dei risultati sè lungo elementi, è ordinato e che esiste una permutazione di che mappa gli elementi nell'elenco di input con quelli dell'elenco di output . Nota che dobbiamo invocare il lemma sopra per dimostrare , che è richiesto da .0 .. n - 1 f ( m ) < nn0..n1lsf(m)<nnth

Si noti tuttavia che è l'utente, ovvero il programmatore, che deve dimostrare il loro algoritmo di ordinamento corretto. Il compilatore non verificherà semplicemente che l'ordinamento sia corretto: tutto ciò che fa è verificare una prova fornita. In effetti, il compilatore non può fare molto di più: le proprietà semantiche come "questo programma è un algoritmo di ordinamento" sono indecidibili (secondo il teorema di Rice), quindi non possiamo sperare di rendere il passaggio di prova completamente automatico.

In un lontano, lontano futuro, possiamo ancora sperare che i dimostratori di teoremi automatici diventino così intelligenti che gli algoritmi "più" praticamente utilizzati possano essere automaticamente dimostrati corretti. Il teorema di Rice afferma solo che ciò non può essere fatto in tutti i casi. Tutto ciò che possiamo sperare è un sistema corretto, ampiamente applicabile, ma intrinsecamente incompleto.

Come nota finale, a volte si dimentica che anche i sistemi di tipo semplice sono incompleti ! Ad esempio anche in Java

int f(int x) {
   if (x+2 != 2+x)
      return "Houston, we have a problem!";
   return 42;
}

è semanticamente sicuro (restituisce sempre un numero intero), ma il controllo del tipo si lamenterà del ritorno irraggiungibile.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.