Ciele
- Formalizovať syntax, sémantiku a typy jazyka NBL.
- Odvodzovať kroky vyhodnotenia a typové úsudky.
- Dokazovať progres a zachovanie typu.
- Porovnať malé a veľké kroky a načrtnúť dôkaz ich ekvivalencie.
Obsah
Na základe predchádzajúcej prednášky o induktívnych výrokoch a uzáveroch na jazyku čísel a pravdivostných hodnôt NBL spojíme induktívne definované tvrdenia s opisom programovacieho jazyka. Definujeme termy, hodnoty, vyhodnocovanie a typové pravidlá. Následne dokážeme jednoznačnosť typu a bezpečnosť vyhodnocovania. Nasledujúca prednáška o zobrazeniach pripraví prostriedky na modelovanie kontextov; NBL premenné ani kontexty nepotrebuje.
- Syntax a konkrétna notácia termov
- Hodnoty, malé kroky, viackrokové vyhodnocovanie a veľké kroky
- Typový systém a typové odvodenia
- Kanonické hodnoty, progres a zachovanie typu
- Ekvivalencia sémantík ako úloha na samostatný dôkaz
NBL – jazyk čísel a pravdivostných hodnôt
Úvod k jazyku NBL
Jazyk NBL je minimalistický jazyk, ktorý kombinuje:
- booleovské hodnoty (
true,false), - prirodzené čísla (
0,succ,pred,iszero), - a základné podmienené výrazy (
if ... then ... else ...).
V systéme Rocq formálne zadefinujeme a analyzujeme:
- syntaktickú štruktúru programu (ako sa termy skladajú),
- sémantiku (ako sa termy vyhodnocujú krok za krokom),
- typový systém, ktorý zaručuje, že "správne typovaný program sa nikdy nezasekne",
- a formálne dokážeme bezpečnosť navrhnutého jazyka.
Postup:
- Syntax jazyka NBL
- Definícia termov a notácie
- Príklady konštrukcie jednoduchých výrazov
- Sémantika (vyhodnotenie)
- Relácia malých krokov (
t → t') - Viackrokové vyhodnotenie (
t →* t') - Prirodzená sémantika veľkých krokov ($t\Downarrow v$)
- Normálne formy
- Relácia malých krokov (
- Typový systém
- Typy:
BoolaNat - Typové pravidlá
- Príklady typovania
- Typy:
- Kanonické hodnoty a základné vety
- Veta o jednoznačnosti typu
- Vety o kanonických hodnotách
- Bezpečnosť jazyka (type soundness)
- Veta o progresii
- Veta o zachovaní typu (preservation)
- Ekvivalencia sémantík
- Znenie vety a slovný náčrt dôkazu
- Samostatné dokončenie formálneho dôkazu v zadaní
Syntax jazyka NBL
Termy zapisujeme v Backusovej–Naurovej forme (BNF). Metapremenná $t$ označuje ľubovoľný term a symbol $\mid$ oddeľuje alternatívy:
Kódové bloky vykonávame postupne v poradí prednášky, v module nbl. Rozlišujeme termy jazyka NBL a výrazy hostiteľského jazyka Rocq.
Definícia v Rocq:
Module nbl.
Inductive nbl : Type :=
| tru : nbl
| fls : nbl
| zro : nbl
| iszro : nbl -> nbl
| prede : nbl -> nbl
| scc : nbl -> nbl
| ite : nbl -> nbl -> nbl -> nbl.
Príklad: Term zadaný abstraktnou syntaxou
Definition p := tru.
Print p. (* p = tru : nbl *)
Notácia pre konkrétnu syntax
Pre lepšiu čitateľnosť definujeme notáciu podobnú syntaxi NBL:
- notácia ako v NBL,
- potrebný vlastný rozsah (scope),
- vlastná gramatika (
custom entry) pre termy NBL
Notácia pre konkrátnu syntax:
Declare Custom Entry tm.
Declare Scope tm_scope.
Notation "'true'" :=
(tru) (in custom tm at level 0): tm_scope.
Notation "'false'" :=
(fls) (in custom tm at level 0): tm_scope.
Notation "<{ e }>" :=
e (e custom tm at level 99): tm_scope.
Notation "( x )" :=
x (in custom tm, x at level 99): tm_scope.
Notation "x" :=
x (in custom tm at level 0, x constr at level 0): tm_scope.
Notation "'0'" :=
(zro) (in custom tm at level 0): tm_scope.
Notation "'succ' x" :=
(scc x) (in custom tm at level 90, x custom tm at level 80): tm_scope.
Notation "'pred' x" :=
(prede x) (in custom tm at level 90, x custom tm at level 80): tm_scope.
Notation "'iszero' x" :=
(iszro x) (in custom tm at level 80, x custom tm at level 70): tm_scope.
Notation "'if' c 'then' t 'else' e" :=
(ite c t e)
(in custom tm at level 90, c custom tm at level 80,
t custom tm at level 80, e custom tm at level 80): tm_scope.
Local Open Scope tm_scope.
Zápis <{ t }> používa vlastnú gramatiku tm na vytvorenie termu NBL. Mimo neho zostávajú true a if ... then ... else ... bežnými výrazmi Rocq. Tieto dve úrovne zápisu preto nezamieňame.
Taktiež je možné využiť abstraktnú syntax z induktívnej definície typu nbl.
Príklad: Rozlíšenie termov NBL a výrazov Rocq
Check true. (* true : bool *)
Check <{ true }>. (* <{ true }> : nbl *)
Check tru. (* <{ true }> : nbl *)
Definition p1 := <{ if true then 0 else true }>.
Check p1. (* p1 : nbl *)
Definition p2 := if true then 0 else 1.
Check p2. (* p2 : nat; podmienka má typ bool v Rocq. *)
Definition p3 := ite tru zro tru.
Check p3. (* p3 : nbl *)
Príkaz Check p1 overuje typ nbl v Rocq, nie správnu typovanosť programu podľa typového systému NBL, ktorý zavedieme nižšie. Termy p1 a p3 sú syntakticky totožné, no v NBL nemajú typ: ich vetvy 0 a true majú odlišné typy.
Hodnoty jazyka NBL
Metapremenná $v$ označuje hodnotu a $nv$ numerickú hodnotu. Hodnotami sú booleovské konštanty alebo numerické hodnoty:
Predikáty $\operatorname{bval}(t)$ a $\operatorname{nval}(t)$ vyjadrujú, že term má príslušný tvar hodnoty. Ich pravidlá sú:
$$ \operatorname{value}(t)\iff\operatorname{nval}(t)\lor\operatorname{bval}(t). $$
Definícia v Rocq:
Inductive bval : nbl -> Prop :=
| bvtrue : bval tru
| bvfalse : bval fls.
Inductive nval : nbl -> Prop :=
| nv0 : nval zro
| nvscc : forall t, nval t -> nval (scc t).
(** Hodnota je numerická alebo booleovská hodnota. *)
Definition value (t : nbl) := nval t \/ bval t.
Štrukturálna operačná sémantika
Nazývaná aj sémantika malých krokov (small step semantics).
Úsudok $t\to t'$ znamená, že term $t$ vykoná jeden krok na $t'$. V Rocq mu zodpovedá t --> t':
$$ \boxed{t\to t'} $$
Nad odvodzovacou čiarou sú premisy, pod ňou záver a napravo názov zodpovedajúceho konštruktora Rocq. Bezpremisové pravidlá možno použiť priamo. Premisu $\operatorname{nval}(v)$ zachovávame explicitne: pravidlá pre predchodcu a test nuly vyžadujú numerickú hodnotu.
Vyhodnocovacie pravidlá:
Definícia v Rocq:
Reserved Notation "t '-->' t'" (at level 40).
Inductive smallstep : nbl -> nbl -> Prop :=
| st_iftrue : forall t1 t2,
<{ if true then t1 else t2 }> --> t1
| st_iffalse : forall t1 t2,
<{ if false then t1 else t2 }> --> t2
| st_if : forall c c' t2 t3,
c --> c' ->
<{ if c then t2 else t3 }> --> <{ if c' then t2 else t3 }>
| st_succ : forall t1 t1',
t1 --> t1' ->
<{ succ t1 }> --> <{ succ t1' }>
| st_pred0 :
<{ pred 0 }> --> <{ 0 }>
| st_predsucc : forall v,
nval v ->
<{ pred (succ v) }> --> v
| st_pred : forall t1 t1',
t1 --> t1' ->
<{ pred t1 }> --> <{ pred t1' }>
| st_iszero0 :
<{ iszero 0 }> --> <{ true }>
| st_iszeronv : forall v,
nval v ->
<{ iszero (succ v) }> --> <{ false }>
| st_iszero : forall t1 t1',
t1 --> t1' ->
<{ iszero t1 }> --> <{ iszero t1' }>
where "t '-->' t'" := (smallstep t t').
#[local] Hint Constructors smallstep : core.
Poznámka
Príkaz #[local] Hint Constructors smallstep : core. definuje, že všetky konštruktory induktívnej relácie smallstep sa majú automaticky používať pri taktikách auto a eauto.
Atribút local obmedzuje hinty na tento modul. V praxi to znamená, že pri pokuse o dôkaz tvrdenia v tvare t --> t' (teda že t vykoná malý krok na t'), Rocq sa pokúsi sám nájsť vhodný konštruktor ako napríklad st_iftrue, st_predsucc, st_iszero, atď.
Príklad: Jeden krok vyhodnotenia
Podmienka true vyberie prvú vetvu v jednom kroku.
$$ \mathsf{if}\ \mathsf{true}\ \mathsf{then}\ \mathsf{succ}\ 0\ \mathsf{else}\ \mathsf{succ}\ 0\to\mathsf{succ}\ 0. $$
Formalizácia a dôkaz v Rocq:
Theorem ex1:
<{if true then succ 0 else succ 0 }> --> <{ succ 0 }>.
Proof.
apply st_iftrue.
Qed.
Print ex1.
Podmienka true vyberie prvú vetvu v jednom kroku.
$$ \mathsf{if}\ \mathsf{true}\ \mathsf{then}\ \mathsf{succ}\ 0\ \mathsf{else}\ \mathsf{succ}\ 0\to\mathsf{succ}\ 0. $$
Formalizácia a dôkaz v Rocq:
Theorem ex1_auto:
<{if true then succ 0 else succ 0 }> --> <{ succ 0 }>.
Proof.
auto. (* Automaticky nájde st_iftrue *)
Qed.
Print ex1_auto.
Reflexívno-tranzitívny uzáver (multi-step)
Relácia multistep opisuje nula alebo viac krokov relácie smallstep. Konštruktor multi_refl predstavuje nula krokov a multi_tran pripája jeden krok pred zvyšok konečnej cesty. Ide o reflexívno-tranzitívny uzáver z prednášky 06; namiesto spájania dvoch celých ciest ho tu definujeme skladaním po jednom kroku.
Matematický zápis $t\to^{*}t'$ zodpovedá multistep t t', resp. t -->* t'. Hviezdička pripúšťa aj nulový počet krokov.
Inductive multistep : nbl -> nbl -> Prop :=
| multi_refl : forall t, multistep t t
| multi_tran : forall t1 t2 t3,
smallstep t1 t2 ->
multistep t2 t3 ->
multistep t1 t3.
Notation "t1 '-->*' t2" := (multistep t1 t2) (at level 40).
#[local] Hint Constructors multistep : core.
Príklad: Viackrokové vyhodnotenie troma spôsobmi
Podmienený výraz sa vo viacerých krokoch vyhodnotí na nulu.
$$ \mathsf{if}\ \mathsf{true}\ \mathsf{then}\ \mathsf{pred}\ 0\ \mathsf{else}\ 0\to^{*}0. $$
Formalizácia a dôkaz v Rocq:
Example ex_multistep :
multistep <{(if true then pred 0 else 0)}> <{0}>.
Proof.
apply multi_tran with (t2 := <{pred 0}>).
- (* ============================
<{ if true then (pred 0) else 0}> --> <{ pred 0 }> *)
apply st_iftrue.
- (* ============================
<{ pred 0 }> -->* <{ 0 }> *)
apply multi_tran with (t2 := <{0}>).
+ (* ============================
<{ pred 0 }> --> <{ 0 }> *)
apply st_pred0.
+ (* ============================
<{ 0 }> -->* <{ 0 }> *)
apply multi_refl.
Qed.
Print ex_multistep.
Rovnaký dôkaz s eauto:
Podmienený výraz sa vo viacerých krokoch vyhodnotí na nulu.
$$ \mathsf{if}\ \mathsf{true}\ \mathsf{then}\ \mathsf{pred}\ 0\ \mathsf{else}\ 0\to^{*}0. $$
Formalizácia a dôkaz v Rocq:
Example ex_multistep_eauto :
multistep <{(if true then pred 0 else 0)}> <{0}>.
Proof.
eauto.
Qed.
Dôkaz s eapply:
Podmienený výraz sa vo viacerých krokoch vyhodnotí na nulu.
$$ \mathsf{if}\ \mathsf{true}\ \mathsf{then}\ \mathsf{pred}\ 0\ \mathsf{else}\ 0\to^{*}0. $$
Formalizácia a dôkaz v Rocq:
Example ex_multistep_eapply :
<{if true then pred 0 else 0}> -->* <{0}>.
Proof.
eapply multi_tran .
- (* ============================
<{ if true then (pred 0) else 0 }> --> ?t2 *)
apply st_iftrue.
- (* ============================
<{ pred 0 }> -->* <{ 0 }> *)
eapply multi_tran.
+ (* ============================
<{ pred 0 }> --> ?t2 *)
apply st_pred0.
+ (* ============================
<{ 0 }> -->* <{ 0 }> *)
apply multi_refl.
Qed.
Prirodzená operačná sémantika (veľké kroky)
Sémantika veľkých krokov opisuje úspešné vyhodnotenie celého termu na výslednú hodnotu. Úsudok čítame „term $t$ sa vyhodnotí na hodnotu $v$“:
$$\boxed{t\Downarrow v}$$
V Rocq ho zapíšeme t ==> v. Relácia bigstep má typ nbl -> nbl -> Prop; to, že jej druhý argument je hodnota, vyplýva z pravidiel, nie zo samotného typu relácie.
Vyhodnocovacie pravidlá:
Pravidlá pre if najprv vyhodnotia podmienku a potom iba vybranú vetvu. Pravidlá pre succ, pred a iszero vyhodnotia argument; pri numerických výsledkoch explicitne požadujú $\operatorname{nval}(nv_1)$. Metapremenná $nv_1$ označuje numerickú hodnotu, zatiaľ čo v deklarácii Rocq je nv1 : nbl obyčajným termom a dôkaz nval nv1 musíme uviesť zvlášť.
Formalizácia v Rocq:
Reserved Notation "t '==>' v" (at level 40).
Inductive bigstep : nbl -> nbl -> Prop :=
| b_true :
<{ true }> ==> <{ true }>
| b_false :
<{ false }> ==> <{ false }>
| b_zero :
<{ 0 }> ==> <{ 0 }>
| b_iftrue : forall t1 t2 t3 v3,
t1 ==> <{ true }> ->
t2 ==> v3 ->
<{ if t1 then t2 else t3 }> ==> v3
| b_iffalse : forall t1 t2 t3 v3,
t1 ==> <{ false }> ->
t3 ==> v3 ->
<{ if t1 then t2 else t3 }> ==> v3
| b_succ : forall t1 nv1,
t1 ==> nv1 ->
nval nv1 ->
<{ succ t1 }> ==> <{ succ nv1 }>
| b_predzero : forall t1,
t1 ==> <{ 0 }> ->
<{ pred t1 }> ==> <{ 0 }>
| b_predsucc : forall t1 nv1,
t1 ==> <{ succ nv1 }> ->
nval nv1 ->
<{ pred t1 }> ==> nv1
| b_iszerozero : forall t1,
t1 ==> <{ 0 }> ->
<{ iszero t1 }> ==> <{ true }>
| b_iszerosucc : forall t1 nv1,
t1 ==> <{ succ nv1 }> ->
nval nv1 ->
<{ iszero t1 }> ==> <{ false }>
where "t '==>' v" := (bigstep t v).
#[local] Hint Constructors bigstep : core.
Príklad: Rovnaký výsledok pomocou veľkých krokov
Výraz z príkladu viackrokového vyhodnotenia sa vyhodnotí na nulu. Podmienka true zvolí prvú vetvu a pravidlo pre predchodcu nuly určí jej výsledok:
$$\mathsf{if}\ \mathsf{true}\ \mathsf{then}\ \mathsf{pred}\ 0\ \mathsf{else}\ 0\Downarrow0.$$
Example ex_bigstep :
<{ if true then pred 0 else 0 }> ==> <{ 0 }>.
Proof.
apply b_iftrue.
- apply b_true.
- apply b_predzero. apply b_zero.
Qed.
Poznámka
Veľký krok opisuje vyhodnotenie až na hodnotu. Relácia $t\to^{*}t'$ však pripúšťa aj zastavenie v medzivýsledku, ktorý ešte nie je hodnotou; obsahuje napríklad nulovú cestu $t\to^{*}t$ pre každý term. Zaseknutý term, napríklad $\mathsf{if}\ 0\ \mathsf{then}\ \mathsf{true}\ \mathsf{else}\ \mathsf{false}$, nemá odvodenie veľkého kroku. Preto pri porovnaní sémantík treba k viackrokovej ceste pripojiť podmienku, že jej koniec je hodnota.
Normálne formy
Term je v normálnej forme, ak nemôže vykonať ďalší krok. Hodnota má tvar určený predikátom value. Zaseknutý term je normálna forma, ktorá nie je hodnotou. Každá hodnota NBL je normálnou formou, opačná implikácia však pre všetky termy neplatí.
$$ \operatorname{normal\_form}(t)\iff\neg\exists t'.\ t\to t'. $$
$$ \operatorname{stuck}(t)\iff\operatorname{normal\_form}(t)\land\neg\operatorname{value}(t). $$
Označenie $\operatorname{stuck}$ používame len v matematickom výklade; v Rocq túto vlastnosť vyjadríme konjunkciou.
Definition normal_form (t : nbl) : Prop :=
~exists t', smallstep t t'.
Tvrdenie, že hodnoty nemajú ďalší krok, dokážeme rozborom ich tvaru a indukciou podľa dôkazu nval:
Každá hodnota je v normálnej forme.
$$ \forall t.\quad\operatorname{value}(t)\implies\operatorname{normal\_form}(t). $$
Formalizácia a dôkaz v Rocq:
Lemma value_normal_form : forall t, value t -> normal_form t.
Proof.
intros t [Hnv | Hbv].
- unfold normal_form. intros [t' Hstep].
generalize dependent t'.
induction Hnv as [| t Hnv IH]; intros t' Hstep.
+ inversion Hstep.
+ inversion Hstep; subst. eapply IH. eassumption.
- unfold normal_form. intros [t' Hstep].
destruct Hbv; inversion Hstep.
Qed.
Príklad: Zaseknutá podmienka
Term if 0 then true else false nie je hodnotou a nemá ďalší krok, pretože nula sa nevyhodnocuje a pravidlá výberu vetvy vyžadujú true alebo false.
Podmienený výraz s nulou na mieste podmienky je zaseknutý.
$$ \operatorname{normal\_form}(\mathsf{if}\ 0\ \mathsf{then}\ \mathsf{true}\ \mathsf{else}\ \mathsf{false})\land\neg\operatorname{value}(\mathsf{if}\ 0\ \mathsf{then}\ \mathsf{true}\ \mathsf{else}\ \mathsf{false}). $$
Formalizácia a dôkaz v Rocq:
Example stuck_if_zero :
normal_form <{ if 0 then true else false }> /\
~ value <{ if 0 then true else false }>.
Proof.
split.
- intros [t' Hstep].
inversion Hstep as [| | c c' t2 t3 Hzero | | | | | | |]; subst.
inversion Hzero.
- intros [Hnv | Hbv].
+ inversion Hnv.
+ inversion Hbv.
Qed.
Príklad: Term s ďalším krokom nie je v normálnej forme
Test nuly na nule môže vykonať krok, a preto nie je v normálnej forme.
$$ \neg\operatorname{normal\_form}(\mathsf{iszero}\ 0). $$
Formalizácia a dôkaz v Rocq:
Theorem ex_normal_form_not_true :
~(normal_form <{iszero 0}>).
Proof.
unfold normal_form.
intros H.
apply H.
exists <{true}>.
apply st_iszero0.
Qed.
Typový systém
Kategóriu typov tvorí booleovský typ a typ prirodzených čísel:
$$ T ::= \mathsf{Bool}\mid\mathsf{Nat}. $$
Typovací úsudok vyjadruje, že term $t$ má typ $T$:
$$ \boxed{\vdash t:T} $$
NBL nemá premenné, takže úsudok nevyžaduje kontext. Zápis $\vdash t:T$ zodpovedá formalizácii <{ |-- t of T }>; nejde o súčasť syntaxe termu ani o príkaz Check hostiteľského systému Rocq.
Typovacie pravidlá:
Definícia v Rocq:
Inductive ty : Type :=
| Bool : ty
| Nat : ty.
Declare Custom Entry ty.
Notation "'Nat'" := Nat (in custom ty).
Notation "'Bool'" := Bool (in custom ty).
Notation "x" := x (in custom ty, x global).
Reserved Notation "<{ '|--' t 'of' T }>"
(at level 0, t custom tm, T custom ty).
Inductive typed : nbl -> ty -> Prop :=
| t_true :
<{ |-- true of Bool }>
| t_false :
<{ |-- false of Bool }>
| t_if : forall t1 t2 t3 T,
<{ |-- t1 of Bool }> ->
<{ |-- t2 of T }> ->
<{ |-- t3 of T }> ->
<{ |-- if t1 then t2 else t3 of T }>
| t_0 :
<{ |-- 0 of Nat }>
| t_succ : forall t1,
<{ |-- t1 of Nat }> ->
<{ |-- succ t1 of Nat }>
| t_pred : forall t1,
<{ |-- t1 of Nat }> ->
<{ |-- pred t1 of Nat }>
| t_iszero : forall t1,
<{ |-- t1 of Nat }> ->
<{ |-- iszero t1 of Bool }>
where "<{ '|--' t 'of' T }>" := (typed t T).
#[local] Hint Constructors typed : core.
Príklad: Typovanie a nemožné typovanie
Booleovská konštanta true má typ Bool.
$$ \vdash\mathsf{true}:\mathsf{Bool}. $$
Formalizácia a dôkaz v Rocq:
Theorem ex3: <{ |-- true of Bool }>.
Proof.
apply t_true.
Qed.
Podmienený výraz s vnoreným testom má typ Bool.
$$ \vdash \mathsf{if}\ \mathsf{true}\ \mathsf{then}\;(\mathsf{if}\ \mathsf{iszero}\ 0\ \mathsf{then}\ \mathsf{true}\ \mathsf{else}\ \mathsf{false})\ \mathsf{else}\ \mathsf{true}:\mathsf{Bool}. $$
Formalizácia a dôkaz v Rocq:
Theorem ex4:
<{|-- if true
then (if iszero 0 then true else false )
else true of Bool }>.
Proof.
apply t_if.
- apply t_true.
- apply t_if.
+ apply t_iszero. apply t_0.
+ apply t_true.
+ apply t_false.
- apply t_true.
Qed.
Podmienený výraz s vnoreným testom má typ Bool.
$$ \vdash \mathsf{if}\ \mathsf{true}\ \mathsf{then}\;(\mathsf{if}\ \mathsf{iszero}\ 0\ \mathsf{then}\ \mathsf{true}\ \mathsf{else}\ \mathsf{false})\ \mathsf{else}\ \mathsf{true}:\mathsf{Bool}. $$
Formalizácia a dôkaz v Rocq:
Theorem ex4_eauto:
<{|-- if true
then (if iszero 0 then true else false )
else true of Bool }>.
Proof.
eauto.
Qed.
Výrazu s vetvami 0 a true nemožno priradiť typ Bool.
$$ \neg\bigl(\vdash\mathsf{if}\ \mathsf{false}\ \mathsf{then}\ 0\ \mathsf{else}\ \mathsf{true}:\mathsf{Bool}\bigr). $$
Formalizácia a dôkaz v Rocq:
Theorem ex5 :
~ <{ |-- if false then 0 else true of Bool }>.
Proof.
unfold not.
intros.
inversion H.
(* H5 : <{ |-- 0 of Bool }> *)
inversion H5.
Qed.
Základné vlastnosti typového systému
Pre tento typový systém NBL dokážeme tri vlastnosti. Jednoznačnosť typu nie je všeobecnou požiadavkou typovej bezpečnosti: napríklad systémy s podtypovaním môžu termu priradiť viac typov. Typovú bezpečnosť tu odvodíme z progresu a zachovania typu.
1. Jednoznačnosť typu (Uniqueness of Types)
Formulácia:
Ak $\vdash t:T_1$ a $\vdash t:T_2$, potom $T_1=T_2$. NBL nemá premenné, preto sú všetky jeho termy uzavreté a typový kontext Γ nepotrebujeme.
- Každý term má najviac jeden typ; netypovateľný term nemá žiadny. Jednoznačnosť typu sama nehovorí nič o deterministickosti vyhodnocovania.
Význam:
- Zjednodušuje dôkazy o správnosti.
- Zaručuje, že kompilátor alebo typová kontrola sa „nerozhoduje" medzi rôznymi typmi toho istého výrazu.
2. Progres (Progress Theorem)
Ak ⊢ t : T, potom buď:
tje už hodnota (value), alebo- existuje
t', takžet --> t'.
Správne typovaný term je hodnotou alebo môže vykonať ďalší krok. Aby sme vylúčili zaseknutie aj po viacerých krokoch, potrebujeme navyše zachovanie typu.
Význam:
- Dobre typované programy nespadnú na runtime chybe typu.
- Typový systém zachytáva chyby ešte pred spustením programu.
3. Stabilita (zachovanie) typu (Preservation Theorem)
Ak $\vdash t:T$ a $t\to t'$, potom $\vdash t':T$.
- Typ sa počas vykonávania programu nezmení.
Význam:
- Každý krok výpočtu zachováva typovú korektnosť.
- Typový systém a sémantika sú v súlade.
Príklad:
- Ak
tmá typNatat --> t', potom ajt'má typNat.
Spolu tieto dve vety – Progress a Preservation – tvoria dôkaz o typovej korektnosti (bezpečnosti jazyka) (z ang. Type Soundness):
"Dobre typované programy sa nikdy nezaseknú a počas behu si zachovávajú správny typ."
Veta o jednoznačnosti typu
Teoretické znenie:
Ak výraz t má typ T1 aj typ T2, potom tieto typy musia byť rovnaké.
Formálne: $$ \forall t,T_1,T_2.\quad(\vdash t:T_1)\land(\vdash t:T_2)\implies T_1=T_2. $$
Dôkaz prebieha štrukturálnou indukciou nad tvarom termu t.
Theorem type_uniqueness Ak má term dva typy, tieto typy sa rovnajú.
$$ \forall t,T_1,T_2.\quad(\vdash t:T_1)\land(\vdash t:T_2)\implies T_1=T_2. $$
Formalizácia a dôkaz v Rocq:
Theorem type_uniqueness: forall t T1 T2,
<{ |-- t of T1 }> /\ <{ |-- t of T2 }> -> T1 = T2.
Proof.
intros.
destruct H as [HT1 HT2]. (* rozdelíme konjunkciu na dva predpoklady *)
(* HT1 : <{ |-- t of T1 }>
HT2 : <{ |-- t of T2 }>
============================
T1 = T2 *)
induction t.
(* dôkaz indukciou podľa štruktúry termu t *)
- (* prípad: t = true *)
inversion HT1. inversion HT2. reflexivity.
(** využitím vety o inverzii odvodíme,
že ak <{ |-- true of T }>, tak T je Bool*)
- (* prípad: t = false *)
inversion HT1. inversion HT2. reflexivity.
(** rovnaké zdôvodnenie ako vyššie *)
- (* prípad: t = 0 *)
inversion HT1. inversion HT2. reflexivity.
(** nula má vždy typ [Nat]. *)
- (* prípad: t = iszero t1 *)
inversion HT1. inversion HT2. reflexivity.
(** test [iszero] má vždy výsledok typu [Bool]. *)
- (* prípad: t = pred t1 *)
inversion HT1. inversion HT2. reflexivity.
(** pravidlo t_pred určí výsledný typ Nat. *)
- (* prípad: t = succ t1 *)
inversion HT1. inversion HT2. reflexivity.
(** pravidlo t_succ určí výsledný typ Nat. *)
- (* prípad: t = if t1 then t2 else t3 *)
inversion HT1; subst.
inversion HT2; subst.
apply IHt2; assumption.
Qed.
Kratší dôkaz Ak má term dva typy, tieto typy sa rovnajú.
$$ \forall t,T_1,T_2.\quad(\vdash t:T_1)\land(\vdash t:T_2)\implies T_1=T_2. $$
Formalizácia a dôkaz v Rocq:
Theorem type_uniqueness': forall t T1 T2,
<{ |-- t of T1 }> /\ <{ |-- t of T2 }> -> T1 = T2.
Proof.
intros.
destruct H as [HT1 HT2].
induction t; inversion HT1; inversion HT2; try reflexivity.
(** Vyriešených prvých 6 prípadov, ostal prípad pre IF *)
- inversion HT1; subst.
inversion HT2; subst.
apply IHt2.
assumption.
assumption.
Qed.
Vety o kanonických hodnotách
Tieto vety sú kľúčovým medzičlánkom medzi typovým systémom a semantikou hodnôt.
Ich úlohou je formálne zachytiť nasledujúcu intuitívnu myšlienku:
Ak je výraz dobre typovaný a je zároveň hodnotou, potom musí mať určitý „kanonický" (štandardný) tvar zodpovedajúci jeho typu.
Inými slovami:
- Hodnota typu
Boolmusí byť buďtruealebofalse. - Hodnota typu
Natmusí byť0alebosucc n, kdenje číselná hodnota.
Lemma bool_canonical
Hodnota typu Bool je booleovskou hodnotou, teda true alebo false.
$$ \forall t.\quad(\vdash t:\mathsf{Bool})\land\operatorname{value}(t)\implies\operatorname{bval}(t). $$
Formalizácia a dôkaz v Rocq:
Lemma bool_canonical : forall t,
<{|-- t of Bool}> /\ value t -> bval t.
Proof.
intros.
unfold value in H.
(* rozbalíme definíciu hodnoty *)
destruct H as [Ht Hbv].
(* rozdelíme konjunkciu typovej relácie
a výroku, že t je hodnota *)
destruct Hbv as [Hnv | Hbv].
(* hodnota môže byť nval alebo bval *)
- (* ============================
Prípad: t je číselná hodnota
Ht : <{ |-- t of Bool }>
Hnv : nval t
============================
bval t *)
inversion Hnv. subst.
+ (* Hnv : nval <{ 0 }>
Ht : <{ |-- 0 of Bool }>
============================
bval <{ 0 }> *)
inversion Ht.
(* t = 0, ale 0 má typ Nat, nie Bool *)
+ (* Druhý konštruktor nval dá tvar succ u a dôkaz nval u.
Rovnosť indexov po subst určí t = succ u.
Názvy pomocných hypotéz môže Rocq generovať odlišne.
Relevantný cieľ po dosadení: bval <{ succ u }>,
pričom typovací predpoklad požaduje typ Bool. *)
subst. inversion Ht.
(* t = succ t má typ Nat, nie Bool *)
- (* ============================
Prípad: t je booleovská hodnota
Ht : <{ |-- t of Bool }>
Hbv : bval t
============================
bval t *)
apply Hbv.
Qed.
Lemma nat_canonical
Analogický postup ako v predchadzajúcom prípade.
Hodnota typu Nat je numerickou hodnotou.
$$ \forall t.\quad(\vdash t:\mathsf{Nat})\land\operatorname{value}(t)\implies\operatorname{nval}(t). $$
Formalizácia a dôkaz v Rocq:
Lemma nat_canonical : forall t,
<{|-- t of Nat}> /\ value t -> nval t.
Proof.
intros.
destruct H as [Ha Hb].
unfold value in Hb.
(* Ha : <{ |-- t of Nat }>
Hb : nval t \/ bval t
============================
nval t *)
destruct Hb as [Hnv | Hbv].
- apply Hnv.
- inversion Hbv. subst.
inversion Ha. subst.
inversion Ha.
Qed.
Dôkaz bezpečnosti jazyka NBL
VETA O PROGRESE (Progress Theorem)
Formulácia:
Ak ⊢ t : T (t. j. výraz t je dobre typovaný), potom buď:
tje hodnota (value), alebo- existuje
t', také žet --> t'(t je možné redukovať).
Význam: Progres poskytuje hodnotu alebo ďalší krok pre aktuálny správne typovaný term. Zachovanie typu umožní túto vlastnosť použiť znovu na výsledok každého kroku.
Každý správne typovaný term je hodnotou alebo môže vykonať ďalší krok.
$$ \forall t,T.\quad(\vdash t:T)\implies\bigl(\operatorname{value}(t)\lor\exists t'.\ t\to t'\bigr). $$
Formalizácia a dôkaz v Rocq:
Theorem progress: forall t T,
<{ |-- t of T}> -> (value t) \/ exists t', (t --> t').
Proof.
intros.
(** Dôkaz indukciou nad typovou reláciou *)
induction H.
(* true *)
- left. unfold value. right. apply bvtrue.
(* false *)
- left. unfold value. right. apply bvfalse.
(* if t1 then t2 else t3 *)
- right. destruct IHtyped1.
+ assert (Hb : bval t1).
{ apply (bool_canonical t1). split; assumption. }
inversion Hb. subst.
* exists t2. apply st_iftrue.
* exists t3. apply st_iffalse.
+ destruct H2 as [t1' Hstep].
exists (<{if t1' then t2 else t3}>).
apply st_if. assumption.
(* 0 *)
- left. unfold value. left. apply nv0.
(* succ t1 *)
- destruct IHtyped.
+ left. assert (nval t1) as Hn.
{ apply (nat_canonical t1).
split. apply H. apply H0. }
unfold value. left. apply nvscc. apply Hn.
+ right. destruct H0 as [t' Hstep].
exists (scc t').
apply st_succ. apply Hstep.
(* pred t1 *)
- destruct IHtyped as [Hv | [t' Hstep]].
+ destruct (nat_canonical t1).
split. assumption. assumption.
right. exists zro. apply st_pred0.
right. exists t. apply st_predsucc. assumption.
+ right. exists (prede t'). apply st_pred. assumption.
(* iszero t1 *)
- destruct IHtyped as [Hv | [t' Hstep]].
+ destruct (nat_canonical t1). split.
* assumption.
* assumption.
* right. exists tru. apply st_iszero0.
* right. exists fls. apply st_iszeronv. assumption.
+ right. exists (iszro t'). apply st_iszero. assumption.
Qed.
VETA O STABILITE (ZACHOVANÍ) TYPU (Type Preservation)
Formulácia:
Ak výraz t má typ T a vykoná jeden krok redukcie na t', potom aj t' má typ T:
$$
\forall t,t',T.\quad(\vdash t:T)\land(t\to t')\implies(\vdash t':T).
$$
Typový systém je konzistentný so sémantikou: každý krok redukcie zachováva typ. Správne typovaný program nikdy „nestratí" svoj typ počas vykonávania.
Túto vetu je možné dokázať dvomi spôsobmi:
- Indukciou na typovej relácii.
- Indukciou na vyhodnocovacej relácii.
Indukcia na typovej relácii:
Jeden krok vyhodnotenia zachováva typ termu.
$$ \forall t,t',T.\quad(\vdash t:T)\land(t\to t')\implies(\vdash t':T). $$
Formalizácia a dôkaz v Rocq:
Theorem preservation: forall t t' T,
<{|-- t of T}> /\ (t-->t') -> <{|-- t' of T}>.
Proof.
intros.
destruct H.
(** rozdelenie konjunkcie na typovací a vyhodnocovací úsudok *)
(* t' zostáva všeobecné: podterm sa redukuje na iný term než celý výraz. *)
generalize dependent t'.
induction H; intros t' Hstep;
inversion Hstep; subst; try assumption.
(* try assumption uzavrelo if-true, if-false aj pred-0.
Zostáva redukcia podmienky if. *)
- apply t_if.
+ apply IHtyped1. assumption.
+ assumption.
+ assumption.
(* succ *)
- apply t_succ. apply IHtyped in H1. assumption.
(* pred (succ v): z typovania succ v získame typ v. *)
- inversion H. assumption.
(* pred *)
- apply t_pred. apply IHtyped. assumption.
(* iszero 0 *)
- apply t_true.
(* iszero (succ v) *)
- apply t_false.
(* iszero *)
- apply t_iszero. apply IHtyped. apply H1.
Qed.
Indukcia na vyhodnocovacej relácii:
Teraz indukcia sleduje všetkých desať vyhodnocovacích pravidiel; inverzia typovania určuje typy podtermov. Typ T musí v indukčnom predpoklade zostať všeobecný: podmienka má typ Bool, aj keď výsledok celého výrazu má typ Nat.
Jeden krok vyhodnotenia zachováva typ termu.
$$ \forall t,t',T.\quad(\vdash t:T)\land(t\to t')\implies(\vdash t':T). $$
Formalizácia a dôkaz v Rocq:
Theorem preservation': forall t t' T,
<{|-- t of T}> /\ (t-->t') -> <{|-- t' of T}>.
Proof.
intros.
destruct H as [Ht Hr].
generalize dependent T.
induction Hr.
- (* if true *)
intros. inversion Ht. subst. assumption.
- (* if false *)
intros. inversion Ht. subst. assumption.
- (* redukcia podmienky if *)
intros. inversion Ht. subst. apply t_if.
+ apply IHHr in H2. assumption.
+ assumption.
+ assumption.
- (* redukcia argumentu succ *)
intros. inversion Ht. subst.
apply IHHr in H0. apply t_succ. assumption.
- (* pred 0 *)
intros. inversion Ht. subst. assumption.
- (* pred (succ v) *)
intros. inversion Ht. subst.
inversion H1. subst. assumption.
- (* redukcia argumentu pred *)
intros. inversion Ht. subst.
apply IHHr in H0. apply t_pred. assumption.
- (* iszero 0 *)
intros. inversion Ht. apply t_true.
- (* iszero (succ v) *)
intros. inversion Ht. apply t_false.
- (* redukcia argumentu iszero *)
intros. inversion Ht. subst.
apply IHHr in H0. apply t_iszero. assumption.
Qed.
Bezpečnosť po viacerých krokoch
Najprv rozšírime zachovanie typu na celú konečnú cestu. Dôkaz prebieha indukciou podľa odvodenia multistep.
Ľubovoľný konečný počet krokov vyhodnotenia zachováva typ.
$$ \forall t,t',T.\quad(\vdash t:T)\land(t\to^{*}t')\implies(\vdash t':T). $$
Formalizácia a dôkaz v Rocq:
Lemma preservation_multistep : forall t t' T,
<{ |-- t of T }> -> t -->* t' -> <{ |-- t' of T }>.
Proof.
intros t t' T Htyped Hmulti.
induction Hmulti as [t | t1 t2 t3 Hstep Hrest IH].
- (* Nula krokov: typ sa nemení. *)
exact Htyped.
- (* Prvý krok zachová typ; na zvyšok cesty použijeme indukčný predpoklad. *)
apply IH.
apply (preservation t1 t2 T).
split; assumption.
Qed.
Ak je term dosiahnutý zo správne typovaného termu v normálnej forme, musí byť hodnotou. Zachovanie typu mu poskytne typ a progres vylúči zaseknutie: možnosť ďalšieho kroku je v rozpore s normálnou formou.
Normálna forma dosiahnutá zo správne typovaného termu je hodnotou.
$$ \forall t,t',T.\quad(\vdash t:T)\land(t\to^{*}t')\land\operatorname{normal\_form}(t')\implies\operatorname{value}(t'). $$
Formalizácia a dôkaz v Rocq:
Theorem type_safety : forall t t' T,
<{ |-- t of T }> -> t -->* t' -> normal_form t' -> value t'.
Proof.
intros t t' T Htyped Hmulti Hnormal.
assert (Htyped' : <{ |-- t' of T }>).
{ apply (preservation_multistep t t' T); assumption. }
destruct (progress t' T Htyped') as [Hv | [t'' Hstep]].
- exact Hv.
- exfalso.
apply Hnormal.
exists t''. exact Hstep.
Qed.
Veta nehovorí, že vyhodnocovanie vždy dosiahne normálnu formu. Ukončenie je samostatná vlastnosť a z progresu ani zachovania typu samotných nevyplýva.
Ekvivalencia malých a veľkých krokov – úloha
Term sa podľa sémantiky veľkých krokov vyhodnotí na $v$ práve vtedy, keď podľa sémantiky malých krokov dosiahne $v$ po konečnom počte krokov a $v$ je hodnota:
$$ \forall t,v.\quad t\Downarrow v\iff\bigl(t\to^{*}v\land\operatorname{value}(v)\bigr). $$
Tvrdenie platí pre všetky termy NBL, nevyžaduje predpoklad správnej typovanosti. Podmienku hodnoty nemožno vypustiť: reflexívna cesta existuje aj pre term, ktorý ešte nie je výsledkom.
Znenie v Rocq na samostatné dokázanie:
Theorem bigstep_smallstep_equiv :
forall t v,
(t ==> v) <-> (t -->* v /\ value v).
Proof.
(* Úloha: doplňte oba smery dôkazu podľa slovného náčrtu. *)
Abort.
Abort tu ukončí rozpracovaný dôkaz bez uloženia vety. Pri riešení úlohy doplňte dôkaz a ukončite ho príkazom Qed. Nejde o hotový dôkaz ani o predpoklad, ktorý by mohli využívať ďalšie vety. V zadaní s booleovským testom hodnôt sa namiesto value v používa isval v = true; pri prepájaní oboch formalizácií treba zohľadniť zhodu tohto testu s predikátom hodnôt.
Slovný náčrt dôkazu:
- Z veľkých krokov na malé kroky. Postupujte indukciou podľa odvodenia $t\Downarrow v$. Základné pravidlá pre
true,falsea nulu dávajú nulovú cestu. V ostatných prípadoch použite indukčné predpoklady na podvýpočty. Pomocnými lemami preneste viackrokové cesty do argumentovsucc,pred,iszeroa do podmienkyif. Pri podmienke potom vykonajte príslušný krok výberu vetvy a pokračujte cestou pre vybranú vetvu; pri číselných operáciách podľa potreby použite pravidlo výpočtu nad numerickou hodnotou. Cesty spojte. Tou istou indukciou overte, že výsledok každého veľkého kroku je hodnota. - Z malých krokov na veľké kroky. Najprv dokážte pomocné tvrdenie: ak $t\to t'$ a $t'\Downarrow v$, potom aj $t\Downarrow v$. Vhodná je indukcia podľa odvodenia jedného malého kroku a inverzia príslušného veľkého kroku. Pripravte si tiež lemu, že každá hodnota sa vyhodnotí sama na seba; pri numerických hodnotách použite indukciu podľa dôkazu
nval. Potom postupujte indukciou podľa cesty $t\to^{*}v$. Nulovú cestu uzavriete pomocou predpokladu, že $v$ je hodnota, a uvedenej lemy. Pri neprázdnej ceste získajte z indukčného predpokladu veľký krok pre jej zvyšok a pomocným tvrdením pridajte prvý malý krok spätne.
Úplný formálny dôkaz oboch smerov aj potrebných pomocných lem je úlohou v študentskom zadaní. Ekvivalencia porovnáva úspešné vyhodnotenie na hodnotu; sama nie je dôkazom, že každý term sa na hodnotu vyhodnotí.
End nbl.
Zhrnutie
Malé kroky opisujú jednotlivé prechody a veľké kroky úspešné vyhodnotenie na hodnotu. Ich ekvivalenciu sme sformulovali ako úlohu so slovným náčrtom dôkazu. Progres a zachovanie typu vylučujú zaseknutie správne typovaných termov.