comparison src/Universes.v @ 377:252ba054a1cd

One more example of avoiding axioms (getNat)
author Adam Chlipala <adam@chlipala.net>
date Wed, 28 Mar 2012 13:20:50 -0400
parents 3322367e955d
children 6413675f8e04
comparison
equal deleted inserted replaced
376:3b36b1e05b4e 377:252ba054a1cd
1 (* Copyright (c) 2009-2011, Adam Chlipala 1 (* Copyright (c) 2009-2012, Adam Chlipala
2 * 2 *
3 * This work is licensed under a 3 * This work is licensed under a
4 * Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 4 * Creative Commons Attribution-Noncommercial-No Derivative Works 3.0
5 * Unported License. 5 * Unported License.
6 * The license text is available at: 6 * The license text is available at:
7 * http://creativecommons.org/licenses/by-nc-nd/3.0/ 7 * http://creativecommons.org/licenses/by-nc-nd/3.0/
8 *) 8 *)
9 9
10 (* begin hide *) 10 (* begin hide *)
11 Require Import List.
12
11 Require Import DepList CpdtTactics. 13 Require Import DepList CpdtTactics.
12 14
13 Set Implicit Arguments. 15 Set Implicit Arguments.
14 (* end hide *) 16 (* end hide *)
15 17
1014 Print Assumptions proj1_again. 1016 Print Assumptions proj1_again.
1015 (** << 1017 (** <<
1016 Closed under the global context 1018 Closed under the global context
1017 >> 1019 >>
1018 1020
1019 This example illustrates again how some of the same design patterns we learned for dependently typed programming can be used fruitfully in theorem statements. *) 1021 This example illustrates again how some of the same design patterns we learned for dependently typed programming can be used fruitfully in theorem statements.
1022
1023 %\medskip%
1024
1025 To close the chapter, we consider one final way to avoid dependence on axioms. Often this task is equivalent to writing definitions such that they %\emph{%#<i>#compute#</i>#%}%. That is, we want Coq's normal reduction to be able to run certain programs to completion. Here is a simple example where such computation can get stuck. In proving properties of such functions, we would need to apply axioms like %\index{axiom K}%K manually to make progress.
1026
1027 Imagine we are working with %\index{deep embedding}%deeply embedded syntax of some programming language, where each term is considered to be in the scope of a number of free variables that hold normal Coq values. To enforce proper typing, we will need to model a Coq typing environment somehow. One natural choice is as a list of types, where variable number [i] will be treated as a reference to the [i]th element of the list. *)
1028
1029 Section withTypes.
1030 Variable types : list Set.
1031
1032 (** To give the semantics of terms, we will need to represent value environments, which assign each variable a term of the proper type. *)
1033
1034 Variable values : hlist (fun x : Set => x) types.
1035
1036 (** Now imagine that we are writing some procedure that operates on a distinguished variable of type [nat]. A hypothesis formalizes this assumption, using the standard library function [nth_error] for looking up list elements by position. *)
1037
1038 Variable natIndex : nat.
1039 Variable natIndex_ok : nth_error types natIndex = Some nat.
1040
1041 (** It is not hard to use this hypothesis to write a function for extracting the [nat] value in position [natIndex] of [values], starting with two helpful lemmas, each of which we finish with [Defined] to mark the lemma as transparent, so that its definition may be expanded during evaluation. *)
1042
1043 Lemma nth_error_nil : forall A n x,
1044 nth_error (@nil A) n = Some x
1045 -> False.
1046 destruct n; simpl; unfold error; congruence.
1047 Defined.
1048
1049 Implicit Arguments nth_error_nil [A n x].
1050
1051 Lemma Some_inj : forall A (x y : A),
1052 Some x = Some y
1053 -> x = y.
1054 congruence.
1055 Defined.
1056
1057 Fixpoint getNat (types' : list Set) (values' : hlist (fun x : Set => x) types')
1058 (natIndex : nat) : (nth_error types' natIndex = Some nat) -> nat :=
1059 match values' with
1060 | HNil => fun pf => match nth_error_nil pf with end
1061 | HCons t ts x values'' =>
1062 match natIndex return nth_error (t :: ts) natIndex = Some nat -> nat with
1063 | O => fun pf =>
1064 match Some_inj pf in _ = T return T with
1065 | refl_equal => x
1066 end
1067 | S natIndex' => getNat values'' natIndex'
1068 end
1069 end.
1070 End withTypes.
1071
1072 (** The problem becomes apparent when we experiment with running [getNat] on a concrete [types] list. *)
1073
1074 Definition myTypes := unit :: nat :: bool :: nil.
1075 Definition myValues : hlist (fun x : Set => x) myTypes :=
1076 tt ::: 3 ::: false ::: HNil.
1077
1078 Definition myNatIndex := 1.
1079
1080 Theorem myNatIndex_ok : nth_error myTypes myNatIndex = Some nat.
1081 reflexivity.
1082 Defined.
1083
1084 Eval compute in getNat myValues myNatIndex myNatIndex_ok.
1085 (** %\vspace{-.15in}%[[
1086 = 3
1087 ]]
1088
1089 We have not hit the problem yet, since we proceeded with a concrete equality proof for [myNatIndex_ok]. However, consider a case where we want to reason about the behavior of [getNat] %\emph{%#<i>#independently#</i>#%}% of a specific proof. *)
1090
1091 Theorem getNat_is_reasonable : forall pf, getNat myValues myNatIndex pf = 3.
1092 intro; compute.
1093 (**
1094 <<
1095 1 subgoal
1096 >>
1097 %\vspace{-.3in}%[[
1098 pf : nth_error myTypes myNatIndex = Some nat
1099 ============================
1100 match
1101 match
1102 pf in (_ = y)
1103 return (nat = match y with
1104 | Some H => H
1105 | None => nat
1106 end)
1107 with
1108 | eq_refl => eq_refl
1109 end in (_ = T) return T
1110 with
1111 | eq_refl => 3
1112 end = 3
1113 ]]
1114
1115 Since the details of the equality proof [pf] are not known, computation can proceed no further. A rewrite with axiom K would allow us to make progress, but we can rethink the definitions a bit to avoid depending on axioms. *)
1116
1117 Abort.
1118
1119 (** Here is a definition of a function that turns out to be useful, though no doubt its purpose will be mysterious for now. A call [update ls n x] overwrites the [n]th position of the list [ls] with the value [x], padding the end of the list with extra [x] values as needed to ensure sufficient length. *)
1120
1121 Fixpoint copies A (x : A) (n : nat) : list A :=
1122 match n with
1123 | O => nil
1124 | S n' => x :: copies x n'
1125 end.
1126
1127 Fixpoint update A (ls : list A) (n : nat) (x : A) : list A :=
1128 match ls with
1129 | nil => copies x n ++ x :: nil
1130 | y :: ls' => match n with
1131 | O => x :: ls'
1132 | S n' => y :: update ls' n' x
1133 end
1134 end.
1135
1136 (** Now let us revisit the definition of [getNat]. *)
1137
1138 Section withTypes'.
1139 Variable types : list Set.
1140 Variable natIndex : nat.
1141
1142 (** Here is the trick: instead of asserting properties about the list [types], we build a %``%#"#new#"#%''% list that is %\emph{%#<i>#guaranteed by construction#</i>#%}% to have those properties. *)
1143
1144 Definition types' := update types natIndex nat.
1145
1146 Variable values : hlist (fun x : Set => x) types'.
1147
1148 (** Now a bit of dependent pattern matching helps us rewrite [getNat] in a way that avoids any use of equality proofs. *)
1149
1150 Fixpoint getNat' (types'' : list Set) (natIndex : nat)
1151 : hlist (fun x : Set => x) (update types'' natIndex nat) -> nat :=
1152 match types'' with
1153 | nil => fun vs => hhd vs
1154 | t :: types0 =>
1155 match natIndex return hlist (fun x : Set => x)
1156 (update (t :: types0) natIndex nat) -> nat with
1157 | O => fun vs => hhd vs
1158 | S natIndex' => fun vs => getNat' types0 natIndex' (htl vs)
1159 end
1160 end.
1161 End withTypes'.
1162
1163 (** Now the surprise comes in how easy it is to %\emph{%#<i>#use#</i>#%}% [getNat']. While typing works by modification of a types list, we can choose parameters so that the modification has no effect. *)
1164
1165 Theorem getNat_is_reasonable : getNat' myTypes myNatIndex myValues = 3.
1166 reflexivity.
1167 Qed.
1168
1169 (** The same parameters as before work without alteration, and we avoid use of axioms. *)